Support 'public' Cm Handle Properties

Add support for new Public Additional Properties list to Register CM Handles API

Issue-ID: CPS-677
Change-Id: I6efc88734da2416f72f71a403622e519398b502d
Signed-off-by: DylanB95EST <dylan.byrne@est.tech>
diff --git a/.gitignore b/.gitignore
index 58f1b2b..624bc1a 100755
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
 *.log.zip
 
 cps-application/archunit_store
+cps-ri/src/main/resources/changelog/db/changes/data/dmi/generated-csv/generated_yang_resource_*
 target/
 log/
 
diff --git a/cps-ncmp-rest/docs/openapi/components.yaml b/cps-ncmp-rest/docs/openapi/components.yaml
index e63f9c0..021a790 100644
--- a/cps-ncmp-rest/docs/openapi/components.yaml
+++ b/cps-ncmp-rest/docs/openapi/components.yaml
@@ -1,5 +1,5 @@
 #  ============LICENSE_START=======================================================
-#  Copyright (C) 2021 Nordix Foundation
+#  Copyright (C) 2021-2022 Nordix Foundation
 #  Modifications Copyright (C) 2021 Pantheon.tech
 #  ================================================================================
 #  Licensed under the Apache License, Version 2.0 (the "License");
@@ -67,12 +67,14 @@
           type: string
           example: my-cm-handle
         cmHandleProperties:
-            $ref: '#/components/schemas/RestCmHandleAdditionalProperties'
-    RestCmHandleAdditionalProperties:
+            $ref: '#/components/schemas/RestCmHandleProperties'
+        publicCmHandleProperties:
+            $ref: '#/components/schemas/RestCmHandleProperties'
+    RestCmHandleProperties:
         type: object
         additionalProperties:
             type: string
-            example: my-additional-property
+            example: my-property
 
     Conditions:
       type: object
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy
index 4addf7b..8d434e7 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy
@@ -1,6 +1,7 @@
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021 Bell Canada
+ *  Modifications Copyright (C) 2021-2022 Nordix Foundation
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -22,10 +23,8 @@
 import com.fasterxml.jackson.databind.ObjectMapper
 import org.onap.cps.TestUtils
 import org.onap.cps.ncmp.api.NetworkCmProxyDataService
-import org.onap.cps.ncmp.api.impl.NetworkCmProxyDataServiceImpl
 import org.onap.cps.ncmp.api.models.CmHandle
 import org.onap.cps.ncmp.api.models.DmiPluginRegistration
-import org.onap.cps.ncmp.api.models.PersistenceCmHandle
 import org.spockframework.spring.SpringBean
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.beans.factory.annotation.Value
diff --git a/cps-ncmp-rest/src/test/resources/dmi-registration.json b/cps-ncmp-rest/src/test/resources/dmi-registration.json
index 24bc9f9..4f27e11 100644
--- a/cps-ncmp-rest/src/test/resources/dmi-registration.json
+++ b/cps-ncmp-rest/src/test/resources/dmi-registration.json
@@ -4,7 +4,10 @@
     {
       "cmHandle": "example-name",
       "cmHandleProperties": {
-          "subSystemId" : "system-001"
+        "subSystemId" : "system-001"
+      },
+      "publicCmHandleProperties": {
+          "area" : "south"
         }
     }
   ]
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
index 3bfb424..bce3ac3 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
@@ -68,11 +68,11 @@
                                                           final String acceptParamInHeader,
                                                           final DataStoreEnum dataStore) {
         final PersistenceCmHandle persistenceCmHandle =
-            cmHandlePropertiesRetriever.retrieveCmHandleDmiServiceNameAndProperties(cmHandle);
+            cmHandlePropertiesRetriever.retrieveCmHandleDmiServiceNameAndDmiProperties(cmHandle);
         final DmiRequestBody dmiRequestBody = DmiRequestBody.builder()
             .operation(READ)
             .build();
-        dmiRequestBody.asCmHandleProperties(persistenceCmHandle.getAdditionalProperties());
+        dmiRequestBody.asDmiProperties(persistenceCmHandle.getDmiProperties());
         final String jsonBody = jsonObjectMapper.asJsonString(dmiRequestBody);
 
         final var dmiResourceDataUrl = getDmiDatastoreUrlWithOptions(
@@ -99,13 +99,13 @@
                                                                              final String requestData,
                                                                              final String dataType) {
         final PersistenceCmHandle persistenceCmHandle =
-            cmHandlePropertiesRetriever.retrieveCmHandleDmiServiceNameAndProperties(cmHandle);
+            cmHandlePropertiesRetriever.retrieveCmHandleDmiServiceNameAndDmiProperties(cmHandle);
         final DmiRequestBody dmiRequestBody = DmiRequestBody.builder()
             .operation(operation)
             .data(requestData)
             .dataType(dataType)
             .build();
-        dmiRequestBody.asCmHandleProperties(persistenceCmHandle.getAdditionalProperties());
+        dmiRequestBody.asDmiProperties(persistenceCmHandle.getDmiProperties());
         final String jsonBody = jsonObjectMapper.asJsonString(dmiRequestBody);
         final String dmiUrl =
             getResourceInDataStoreUrl(persistenceCmHandle.resolveDmiServiceName(DATA),
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java
index 1ce6dcf..657b0b4 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java
@@ -49,11 +49,11 @@
      *
      * @param dmiRestClient {@code DmiRestClient}
      */
-    public DmiModelOperations(final PersistenceCmHandleRetriever cmHandlePropertiesRetriever,
+    public DmiModelOperations(final PersistenceCmHandleRetriever dmiPropertiesRetriever,
                               final JsonObjectMapper jsonObjectMapper,
                               final NcmpConfiguration.DmiProperties dmiProperties,
                               final DmiRestClient dmiRestClient) {
-        super(cmHandlePropertiesRetriever, jsonObjectMapper, dmiProperties, dmiRestClient);
+        super(dmiPropertiesRetriever, jsonObjectMapper, dmiProperties, dmiRestClient);
     }
 
     /**
@@ -65,7 +65,7 @@
     public List<ModuleReference> getModuleReferences(final PersistenceCmHandle persistenceCmHandle) {
         final DmiRequestBody dmiRequestBody = DmiRequestBody.builder()
             .build();
-        dmiRequestBody.asCmHandleProperties(persistenceCmHandle.getAdditionalProperties());
+        dmiRequestBody.asDmiProperties(persistenceCmHandle.getDmiProperties());
         final ResponseEntity<Object> dmiFetchModulesResponseEntity = getResourceFromDmiWithJsonData(
             persistenceCmHandle.resolveDmiServiceName(MODEL),
                 jsonObjectMapper.asJsonString(dmiRequestBody), persistenceCmHandle.getId(), "modules");
@@ -81,11 +81,11 @@
      */
     public Map<String, String> getNewYangResourcesFromDmi(final PersistenceCmHandle persistenceCmHandle,
                                                           final List<ModuleReference> unknownModuleReferences) {
-        final String jsonDataWithDataAndCmHandleProperties = getRequestBodyToFetchYangResources(
-            unknownModuleReferences, persistenceCmHandle.getAdditionalProperties());
+        final String jsonWithDataAndDmiProperties = getRequestBodyToFetchYangResources(
+            unknownModuleReferences, persistenceCmHandle.getDmiProperties());
         final ResponseEntity<Object> responseEntity = getResourceFromDmiWithJsonData(
             persistenceCmHandle.resolveDmiServiceName(MODEL),
-            jsonDataWithDataAndCmHandleProperties,
+            jsonWithDataAndDmiProperties,
             persistenceCmHandle.getId(),
             "moduleResources");
         return asModuleNameToYangResourceMap(responseEntity);
@@ -109,13 +109,13 @@
     }
 
     private static String getRequestBodyToFetchYangResources(final List<ModuleReference> unknownModuleReferences,
-        final List<PersistenceCmHandle.AdditionalProperty> cmHandleProperties) {
+        final List<PersistenceCmHandle.Property> dmiProperties) {
         final JsonArray moduleReferencesAsJson = getModuleReferencesAsJson(unknownModuleReferences);
         final JsonObject data = new JsonObject();
         data.add("modules", moduleReferencesAsJson);
         final JsonObject jsonRequestObject = new JsonObject();
         jsonRequestObject.add("data", data);
-        jsonRequestObject.add("cmHandleProperties", toJsonObject(cmHandleProperties));
+        jsonRequestObject.add("cmHandleProperties", toJsonObject(dmiProperties));
         return jsonRequestObject.toString();
     }
 
@@ -131,9 +131,10 @@
         return moduleReferences;
     }
 
-    private static JsonObject toJsonObject(final List<PersistenceCmHandle.AdditionalProperty> cmHandleProperties) {
+    private static JsonObject toJsonObject(final List<PersistenceCmHandle.Property>
+                                               dmiProperties) {
         final JsonObject asJsonObject = new JsonObject();
-        for (final PersistenceCmHandle.AdditionalProperty additionalProperty : cmHandleProperties) {
+        for (final PersistenceCmHandle.Property additionalProperty : dmiProperties) {
             asJsonObject.addProperty(additionalProperty.getName(), additionalProperty.getValue());
         }
         return asJsonObject;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiRequestBody.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiRequestBody.java
index 26feeea..1066eac 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiRequestBody.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiRequestBody.java
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2021 Nordix Foundation
+ *  Copyright (C) 2021-2022 Nordix Foundation
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -21,8 +21,8 @@
 package org.onap.cps.ncmp.api.impl.operations;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonValue;
-import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -40,7 +40,7 @@
         UPDATE("update"),
         PATCH("patch"),
         DELETE("delete");
-        private String value;
+        private final String value;
 
         OperationEnum(final String value) {
             this.value = value;
@@ -56,25 +56,19 @@
     private OperationEnum operation;
     private String dataType;
     private String data;
-    private Map<String, String> cmHandleProperties;
+    @JsonProperty("cmHandleProperties")
+    private Map<String, String> dmiProperties;
 
     /**
-     * Set CmHandleProperties by converting a list of PersistenceCmHandle.AdditionalProperty objects.
+     * Set DMI Properties by converting a list of PersistenceCmHandle.Property objects.
      *
-     * @param cmHandlePropertiesAsList the cm handle additional properties
+     * @param dmiPropertiesAsList list of cm handle dmi properties
      */
-    public void asCmHandleProperties(
-        final List<PersistenceCmHandle.AdditionalProperty> cmHandlePropertiesAsList) {
-        final boolean isCmHandlePropertiesNullOrEmpty =
-            cmHandlePropertiesAsList == null || cmHandlePropertiesAsList.isEmpty();
-        if (isCmHandlePropertiesNullOrEmpty) {
-            cmHandleProperties = Collections.emptyMap();
-        } else {
-            cmHandleProperties = new LinkedHashMap<>();
-            for (final PersistenceCmHandle.AdditionalProperty additionalProperty : cmHandlePropertiesAsList) {
-                cmHandleProperties.put(additionalProperty.getName(),
-                    additionalProperty.getValue());
-            }
+    public void asDmiProperties(
+        final List<PersistenceCmHandle.Property> dmiPropertiesAsList) {
+        dmiProperties = new LinkedHashMap<>();
+        for (final PersistenceCmHandle.Property dmiProperty : dmiPropertiesAsList) {
+            dmiProperties.put(dmiProperty.getName(), dmiProperty.getValue());
         }
     }
 
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/PersistenceCmHandleRetriever.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/PersistenceCmHandleRetriever.java
index 78b5c31..c489eef 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/PersistenceCmHandleRetriever.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/PersistenceCmHandleRetriever.java
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2021 Nordix Foundation
+ *  Copyright (C) 2021-2022 Nordix Foundation
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -20,9 +20,9 @@
 
 package org.onap.cps.ncmp.api.impl.operations;
 
-import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import lombok.AllArgsConstructor;
 import org.onap.cps.api.CpsDataService;
 import org.onap.cps.ncmp.api.models.CmHandle;
 import org.onap.cps.ncmp.api.models.PersistenceCmHandle;
@@ -34,30 +34,24 @@
  * Retrieves PersistenceCmHandles & properties.
  */
 @Component
+@AllArgsConstructor
 public class PersistenceCmHandleRetriever {
 
     private static final String NCMP_DATASPACE_NAME = "NCMP-Admin";
     private static final String NCMP_DMI_REGISTRY_ANCHOR = "ncmp-dmi-registry";
 
-    private CpsDataService cpsDataService;
+    private final CpsDataService cpsDataService;
 
     /**
-     * Constructor for PersistenceCmHandleRetriever.
-     * 
-     * @param cpsDataService the cps data service.
-     */
-    public PersistenceCmHandleRetriever(final CpsDataService cpsDataService) {
-        this.cpsDataService = cpsDataService;
-    }
-
-    /**
-     * This method retieves dmi service name and properties for a given cm handle.
+     * This method retrieves DMI service name and DMI properties for a given cm handle.
      * @param cmHandleId the id of the cm handle
      * @return persistence cm handle
      */
-    public PersistenceCmHandle retrieveCmHandleDmiServiceNameAndProperties(final String cmHandleId) {
+    public PersistenceCmHandle retrieveCmHandleDmiServiceNameAndDmiProperties(final String cmHandleId) {
         final DataNode cmHandleDataNode = getCmHandleDataNode(cmHandleId);
-        final CmHandle cmHandle = new CmHandle(cmHandleId, getCmHandleProperties(cmHandleDataNode));
+        final CmHandle cmHandle = new CmHandle();
+        cmHandle.setCmHandleID(cmHandleId);
+        populateCmHandleDmiProperties(cmHandleDataNode, cmHandle);
         return PersistenceCmHandle.toPersistenceCmHandle(
             String.valueOf(cmHandleDataNode.getLeaves().get("dmi-service-name")),
             String.valueOf(cmHandleDataNode.getLeaves().get("dmi-data-service-name")),
@@ -74,16 +68,19 @@
             FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
     }
 
-    private static Map<String, String> getCmHandleProperties(final DataNode cmHandleDataNode) {
-        if (cmHandleDataNode.getChildDataNodes().isEmpty()) {
-            return Collections.emptyMap();
-        }
-        final Map<String, String> cmHandlePropertiesAsMap = new LinkedHashMap<>();
+    private static void populateCmHandleDmiProperties(final DataNode cmHandleDataNode, final CmHandle cmHandle) {
+        final Map<String, String> dmiProperties = new LinkedHashMap<>();
         for (final DataNode childDataNode: cmHandleDataNode.getChildDataNodes()) {
-            cmHandlePropertiesAsMap.put(String.valueOf(childDataNode.getLeaves().get("name")),
-                String.valueOf(childDataNode.getLeaves().get("value")));
+            if (childDataNode.getXpath().contains("/additional-properties[@name=")) {
+                addProperty(childDataNode, dmiProperties);
+            }
         }
-        return cmHandlePropertiesAsMap;
+        cmHandle.setDmiProperties(dmiProperties);
+    }
+
+    private static void addProperty(final DataNode propertyDataNode, final Map<String, String> propertiesAsMap) {
+        propertiesAsMap.put(String.valueOf(propertyDataNode.getLeaves().get("name")),
+            String.valueOf(propertyDataNode.getLeaves().get("value")));
     }
 
 }
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandle.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandle.java
index a38442b..9a9b6fa 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandle.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandle.java
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2021 Nordix Foundation
+ *  Copyright (C) 2021-2022 Nordix Foundation
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -21,8 +21,10 @@
 package org.onap.cps.ncmp.api.models;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonSetter;
+import com.fasterxml.jackson.annotation.Nulls;
+import java.util.Collections;
 import java.util.Map;
-import lombok.AllArgsConstructor;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
 import lombok.Setter;
@@ -34,13 +36,18 @@
 @Validated
 @Getter
 @Setter
-@AllArgsConstructor
 @NoArgsConstructor
 public class CmHandle {
 
     @JsonProperty("cmHandle")
     private String cmHandleID;
 
-    private Map<String, String> cmHandleProperties;
+    @JsonSetter(nulls = Nulls.AS_EMPTY)
+    @JsonProperty("cmHandleProperties")
+    private Map<String, String> dmiProperties = Collections.emptyMap();
+
+    @JsonSetter(nulls = Nulls.AS_EMPTY)
+    @JsonProperty("publicCmHandleProperties")
+    private Map<String, String> publicProperties = Collections.emptyMap();
 
 }
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/PersistenceCmHandle.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/PersistenceCmHandle.java
index 8b959e3..cc32bb7 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/PersistenceCmHandle.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/PersistenceCmHandle.java
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2021 Nordix Foundation
+ *  Copyright (C) 2021-2022 Nordix Foundation
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -24,7 +24,6 @@
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.google.common.base.Strings;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import lombok.AllArgsConstructor;
@@ -54,7 +53,10 @@
     private String dmiModelServiceName;
 
     @JsonProperty("additional-properties")
-    private List<AdditionalProperty> additionalProperties;
+    private List<Property> dmiProperties;
+
+    @JsonProperty("public-properties")
+    private List<Property> publicProperties;
 
     /**
      * Create a persistenceCmHandle.
@@ -73,26 +75,12 @@
         persistenceCmHandle.setDmiServiceName(dmiServiceName);
         persistenceCmHandle.setDmiDataServiceName(dmiDataServiceName);
         persistenceCmHandle.setDmiModelServiceName(dmiModelServiceName);
-        if (cmHandle.getCmHandleProperties() == null) {
-            persistenceCmHandle.asAdditionalProperties(Collections.emptyMap());
-        } else {
-            persistenceCmHandle.asAdditionalProperties(cmHandle.getCmHandleProperties());
-        }
+        persistenceCmHandle.setDmiProperties(asPersistenceCmHandleProperties(cmHandle.getDmiProperties()));
+        persistenceCmHandle.setPublicProperties(asPersistenceCmHandleProperties(cmHandle.getPublicProperties()));
         return persistenceCmHandle;
     }
 
     /**
-     * Set Additional Properties map, key and value pair.
-     * @param additionalPropertiesAsMap Map of Additional Properties
-     */
-    public void asAdditionalProperties(final Map<String, String> additionalPropertiesAsMap) {
-        additionalProperties = new ArrayList<>(additionalPropertiesAsMap.size());
-        for (final Map.Entry<String, String> entry : additionalPropertiesAsMap.entrySet()) {
-            additionalProperties.add(new AdditionalProperty(entry.getKey(), entry.getValue()));
-        }
-    }
-
-    /**
      * Resolve a dmi service name.
      * @param requiredService indicates what typo of service is required
      * @return dmi service name
@@ -107,13 +95,21 @@
         return dmiServiceName;
     }
 
+    private static List<Property> asPersistenceCmHandleProperties(final Map<String, String> propertiesAsMap) {
+        final List<Property> persistenceCmHandleProperties = new ArrayList<>(propertiesAsMap.size());
+        for (final Map.Entry<String, String> entry : propertiesAsMap.entrySet()) {
+            persistenceCmHandleProperties.add(new PersistenceCmHandle.Property(entry.getKey(), entry.getValue()));
+        }
+        return persistenceCmHandleProperties;
+    }
+
     private static boolean isNullEmptyOrBlank(final String serviceName) {
         return Strings.isNullOrEmpty(serviceName) || serviceName.isBlank();
     }
 
     @AllArgsConstructor
     @Data
-    public static class AdditionalProperty {
+    public static class Property {
 
         @JsonProperty()
         private final String name;
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplModelSyncSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplModelSyncSpec.groovy
index 4647571..67108a5 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplModelSyncSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplModelSyncSpec.groovy
@@ -24,6 +24,7 @@
 import org.onap.cps.api.CpsModuleService
 import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations
 import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations
+import org.onap.cps.ncmp.api.models.CmHandle
 import org.onap.cps.ncmp.api.models.PersistenceCmHandle
 import org.onap.cps.spi.model.ModuleReference
 import org.onap.cps.utils.JsonObjectMapper
@@ -44,30 +45,29 @@
 
     def 'Sync model for a (new) cm handle with #scenario'() {
         given: 'persistence cm handle is given'
-            def cmHandleForModelSync = new PersistenceCmHandle(id:'some cm handle', dmiServiceName: 'some service name')
-        and: 'additional properties are set as required'
-            if (additionalProperties!=null) {
-                cmHandleForModelSync.asAdditionalProperties(additionalProperties)
-            }
-        and: 'dmi operations returns some module references'
+            def cmHandle = new CmHandle()
+            def dmiServiceName = 'some service name'
+            cmHandle.cmHandleID = 'cm handle id 1'
+            cmHandle.dmiProperties = dmiProperties
+            def persistenceCmHandle = PersistenceCmHandle.toPersistenceCmHandle(dmiServiceName, '' , '', cmHandle)
+        and: 'DMI operations returns some module references'
             def moduleReferences =  [ new ModuleReference(moduleName:'module1',revision:'1'),
                                                             new ModuleReference(moduleName:'module2',revision:'2') ]
-            mockDmiModelOperations.getModuleReferences(cmHandleForModelSync) >> moduleReferences
+            mockDmiModelOperations.getModuleReferences(persistenceCmHandle) >> moduleReferences
         and: 'CPS-Core returns list of existing module resources'
             mockCpsModuleService.getYangResourceModuleReferences(expectedDataspaceName) >> existingModuleResourcesInCps
         and: 'DMI-Plugin returns resource(s) for "new" module(s)'
-            mockDmiModelOperations.getNewYangResourcesFromDmi(cmHandleForModelSync, [new ModuleReference('module1', '1')]) >> yangResourceToContentMap
+            mockDmiModelOperations.getNewYangResourcesFromDmi(persistenceCmHandle, [new ModuleReference('module1', '1')]) >> yangResourceToContentMap
         when: 'module sync is triggered'
-            objectUnderTest.syncModulesAndCreateAnchor(cmHandleForModelSync)
+            objectUnderTest.syncModulesAndCreateAnchor(persistenceCmHandle)
         then: 'the CPS module service is called once with the correct parameters'
-            1 * mockCpsModuleService.createSchemaSetFromModules(expectedDataspaceName, cmHandleForModelSync.getId(), yangResourceToContentMap, expectedKnownModules)
+            1 * mockCpsModuleService.createSchemaSetFromModules(expectedDataspaceName, persistenceCmHandle.getId(), yangResourceToContentMap, expectedKnownModules)
         and: 'admin service create anchor method has been called with correct parameters'
-            1 * mockCpsAdminService.createAnchor(expectedDataspaceName, cmHandleForModelSync.getId(), cmHandleForModelSync.getId())
+            1 * mockCpsAdminService.createAnchor(expectedDataspaceName, persistenceCmHandle.getId(), persistenceCmHandle.getId())
         where: 'the following parameters are used'
-            scenario                        | additionalProperties | existingModuleResourcesInCps                                               | yangResourceToContentMap      || expectedKnownModules                                                       | expectedJsonForAdditionalProperties
-            'one unknown module'            | ['name1': 'value1']  | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | [module1: 'some yang source'] || [new ModuleReference('module2', '2')]                                      | '{"name1":"value1"}'
-            'no add. properties'            | [:]                  | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | [module1: 'some yang source'] || [new ModuleReference('module2', '2')]                                      | '{}'
-            'additional properties is null' | null                 | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | [module1: 'some yang source'] || [new ModuleReference('module2', '2')]                                      | '{}'
-            'no unknown module'             | [:]                  | [new ModuleReference('module1', '1'), new ModuleReference('module2', '2')] | [:]                           || [new ModuleReference('module1', '1'), new ModuleReference('module2', '2')] | '{}'
+            scenario                        | dmiProperties        | existingModuleResourcesInCps                                               | yangResourceToContentMap      || expectedKnownModules
+            'one unknown module'            | ['name1': 'value1']  | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | [module1: 'some yang source'] || [new ModuleReference('module2', '2')]
+            'no add. properties'            | [:]                  | [new ModuleReference('module2', '2'), new ModuleReference('module3', '3')] | [module1: 'some yang source'] || [new ModuleReference('module2', '2')]
+            'no unknown module'             | [:]                  | [new ModuleReference('module1', '1'), new ModuleReference('module2', '2')] | [:]                           || [new ModuleReference('module1', '1'), new ModuleReference('module2', '2')]
     }
 }
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
index b954b41..3ec6f3a 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
@@ -60,11 +60,15 @@
             def objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
             def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin:'my-server')
             persistenceCmHandle.cmHandleID = '123'
-            persistenceCmHandle.cmHandleProperties = [name1: 'value1', name2: 'value2']
+            persistenceCmHandle.dmiProperties = [dmiProp1: 'dmiValue1', dmiProp2: 'dmiValue2']
+            persistenceCmHandle.publicProperties = [publicProp1: 'publicValue1', publicProp2: 'publicValue2' ]
             dmiPluginRegistration.createdCmHandles = createdCmHandles
             dmiPluginRegistration.updatedCmHandles = updatedCmHandles
             dmiPluginRegistration.removedCmHandles = removedCmHandles
-            def expectedJsonData = '{"cm-handles":[{"id":"123","dmi-service-name":"my-server","dmi-data-service-name":null,"dmi-model-service-name":null,"additional-properties":[{"name":"name1","value":"value1"},{"name":"name2","value":"value2"}]}]}'
+            def expectedJsonData = '{"cm-handles":[{"id":"123","dmi-service-name":"my-server","dmi-data-service-name":null,"dmi-model-service-name":null,' +
+                '"additional-properties":[{"name":"dmiProp1","value":"dmiValue1"},{"name":"dmiProp2","value":"dmiValue2"}],' +
+                '"public-properties":[{"name":"publicProp1","value":"publicValue1"},{"name":"publicProp2","value":"publicValue2"}]' +
+                '}]}'
         when: 'registration is updated and modules are synced'
             objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
         then: 'save list elements is invoked with the expected parameters'
@@ -87,14 +91,15 @@
             'no valid data'             | null                  | null                  | null             || 0                       | 0                         | 0
     }
 
-    def 'Register a DMI Plugin for the given cm-handle(s) without additional properties.'() {
+    def 'Register a DMI Plugin for the given cm-handle(s) without DMI properties.'() {
         given: 'a registration without cm-handle properties'
             NetworkCmProxyDataServiceImpl objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
             def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin:'my-server')
             persistenceCmHandle.cmHandleID = '123'
-            persistenceCmHandle.cmHandleProperties = null
+            persistenceCmHandle.dmiProperties = Collections.emptyMap()
+            persistenceCmHandle.publicProperties = Collections.emptyMap()
             dmiPluginRegistration.createdCmHandles = [persistenceCmHandle]
-            def expectedJsonData = '{"cm-handles":[{"id":"123","dmi-service-name":"my-server","dmi-data-service-name":null,"dmi-model-service-name":null,"additional-properties":[]}]}'
+            def expectedJsonData = '{"cm-handles":[{"id":"123","dmi-service-name":"my-server","dmi-data-service-name":null,"dmi-model-service-name":null,"additional-properties":[],"public-properties":[]}]}'
         when: 'registration is updated'
             objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
         then: 'save list elements is invoked with the expected parameters'
@@ -163,7 +168,7 @@
             'data & model using same service' | ''         | 'service1'     | 'service1'
     }
 
-    def 'Invalid dmi plugin registration with #scenario'() {
+    def 'Invalid DMI plugin registration with #scenario'() {
         given: 'a registration '
             def objectUnderTest = getObjectUnderTestWithModelSyncDisabled()
             def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin:dmiPlugin, dmiModelPlugin:dmiModelPlugin,
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
index 51af0f5..7f12700 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
@@ -57,34 +57,28 @@
 
     def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']"
 
+    def dataNode = new DataNode(leaves: ['dmi-service-name': 'testDmiService'])
 
-    def 'Write resource data for pass-through running from dmi using POST #scenario cm handle properties.'() {
-        given: 'a data node'
-            def dataNode = getDataNode(includeCmHandleProperties)
-        and: 'cpsDataService returns valid datanode'
+
+    def 'Write resource data for pass-through running from DMI using POST #scenario cm handle properties.'() {
+        given: 'cpsDataService returns valid datanode'
             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
         when: 'get resource data is called'
             objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
                 'testResourceId', CREATE,
                 '{some-json}', 'application/json')
-        then: 'dmi called with correct data'
+        then: 'DMI called with correct data'
             1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId',
                 CREATE, '{some-json}', 'application/json')
                 >> { new ResponseEntity<>(HttpStatus.CREATED) }
-        where:
-            scenario  | includeCmHandleProperties || expectedJsonForCmhandleProperties
-            'with'    | true                      || '{"testName":"testValue"}'
-            'without' | false                     || '{}'
     }
 
-    def 'Write resource data for pass-through running from dmi using POST "not found" response (from DMI).'() {
-        given: 'a data node'
-            def dataNode = getDataNode(true)
-        and: 'cpsDataService returns valid dataNode'
+    def 'Write resource data for pass-through running from DMI using POST "not found" response (from DMI).'() {
+        given: 'cpsDataService returns valid dataNode'
             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
-        and: 'dmi returns a response with 404 status code'
+        and: 'DMI returns a response with 404 status code'
             mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle',
                 'testResourceId', CREATE,
                 '{some-json}', 'application/json')
@@ -100,13 +94,11 @@
     }
 
 
-    def 'Get resource data for pass-through operational from dmi.'() {
-        given: 'a data node'
-            def dataNode = getDataNode(true)
-        and: 'get data node is called'
+    def 'Get resource data for pass-through operational from DMI.'() {
+        given: 'get data node is called'
             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
-        and: 'get resource data from dmi is called'
+        and: 'get resource data from DMI is called'
             mockDmiDataOperations.getResourceDataFromDmi(
                 'testCmHandle',
                 'testResourceId',
@@ -118,19 +110,17 @@
                 'testResourceId',
                 'testAcceptParam',
                 '(a=1,b=2)')
-        then: 'dmi returns a json response'
+        then: 'DMI returns a json response'
             response == 'result-json'
     }
 
-    def 'Get resource data for pass-through operational from dmi with Json Processing Exception.'() {
-        given: 'a data node'
-            def dataNode = getDataNode(true)
-        and: 'cps data service returns valid data node'
+    def 'Get resource data for pass-through operational from DMI with Json Processing Exception.'() {
+        given: 'cps data service returns valid data node'
             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
         and: 'objectMapper not able to parse object'
             spiedJsonObjectMapper.asJsonString(_) >> { throw new JsonProcessingException('testException') }
-        and: 'dmi returns NOK response'
+        and: 'DMI returns NOK response'
             mockDmiDataOperations.getResourceDataFromDmi(*_)
                 >> new ResponseEntity<>('NOK-json', HttpStatus.NOT_FOUND)
         when: 'get resource data is called'
@@ -143,13 +133,11 @@
             exceptionThrown.details == 'DMI status code: 404, DMI response body: NOK-json'
     }
 
-    def 'Get resource data for pass-through operational from dmi return NOK response.'() {
-        given: 'a data node'
-            def dataNode = getDataNode(true)
-        and: 'cps data service returns valid data node'
+    def 'Get resource data for pass-through operational from DMI return NOK response.'() {
+        given: 'cps data service returns valid data node'
             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
-        and: 'dmi returns NOK response'
+        and: 'DMI returns NOK response'
             mockDmiDataOperations.getResourceDataFromDmi('testCmHandle',
                 'testResourceId',
                 '(a=1,b=2)',
@@ -167,13 +155,11 @@
             exceptionThrown.details.contains('NOK-json')
     }
 
-    def 'Get resource data for pass-through running from dmi.'() {
-        given: 'a data node'
-            def dataNode = getDataNode(true)
-        and: 'cpsDataService returns valid data node'
+    def 'Get resource data for pass-through running from DMI.'() {
+        given: 'cpsDataService returns valid data node'
             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
-        and: 'dmi returns valid response and data'
+        and: 'DMI returns valid response and data'
             mockDmiDataOperations.getResourceDataFromDmi('testCmHandle',
                 'testResourceId',
                 '(a=1,b=2)',
@@ -188,13 +174,11 @@
             response == '{result-json}'
     }
 
-    def 'Get resource data for pass-through running from dmi return NOK response.'() {
-        given: 'a data node'
-            def dataNode = getDataNode(true)
-        and: 'cpsDataService returns valid dataNode'
+    def 'Get resource data for pass-through running from DMI return NOK response.'() {
+        given: 'cpsDataService returns valid dataNode'
             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
-        and: 'dmi returns NOK response'
+        and: 'DMI returns NOK response'
             mockDmiDataOperations.getResourceDataFromDmi('testCmHandle',
                 'testResourceId',
                 '(a=1,b=2)',
@@ -226,25 +210,18 @@
             1 * mockCpsAdminService.queryAnchorNames('NFP-Operational', ['some-module-name'])
     }
 
-
-    def 'Update resource data for pass-through running from dmi using POST #scenario cm handle properties.'() {
-        given: 'a data node'
-            def dataNode = getDataNode(includeCmHandleProperties)
-        and: 'cpsDataService returns valid datanode'
+    def 'Update resource data for pass-through running from dmi using POST #scenario DMI properties.'() {
+        given: 'cpsDataService returns valid datanode'
             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
                 cmHandleXPath, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
         when: 'get resource data is called'
             objectUnderTest.writeResourceDataPassThroughRunningForCmHandle('testCmHandle',
                 'testResourceId', UPDATE,
                 '{some-json}', 'application/json')
-        then: 'dmi called with correct data'
+        then: 'DMI called with correct data'
             1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId',
                 UPDATE, '{some-json}', 'application/json')
                 >> { new ResponseEntity<>(HttpStatus.OK) }
-        where:
-            scenario  | includeCmHandleProperties || expectedJsonForCmhandleProperties
-            'with'    | true                      || '{"testName":"testValue"}'
-            'without' | false                     || '{}'
     }
 
     def 'Verify error message from handleResponse is correct for #scenario operation.'() {
@@ -252,7 +229,7 @@
             mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi(*_)
                 >> new ResponseEntity<>(HttpStatus.NOT_FOUND)
         when: 'get resource data is called'
-            def response = objectUnderTest.writeResourceDataPassThroughRunningForCmHandle(
+            objectUnderTest.writeResourceDataPassThroughRunningForCmHandle(
                 'testCmHandle',
                 'testResourceId',
                 givenOperation,
@@ -267,15 +244,4 @@
             'READ'   | READ           || 'Not able to read resource data.'
             'UPDATE' | UPDATE         || 'Not able to update resource data.'
     }
-
-    def getDataNode(boolean includeCmHandleProperties) {
-        def dataNode = new DataNode()
-        dataNode.leaves = ['dmi-service-name': 'testDmiService']
-        if (includeCmHandleProperties) {
-            def cmHandlePropertyDataNode = new DataNode()
-            cmHandlePropertyDataNode.leaves = ['name': 'testName', 'value': 'testValue']
-            dataNode.childDataNodes = [cmHandlePropertyDataNode]
-        }
-        return dataNode
-    }
 }
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy
index 54ae0aa..7873f39 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiDataOperationsSpec.groovy
@@ -47,30 +47,29 @@
 
     def 'call get resource data for #expectedDatastoreInUrl from DMI #scenario.'() {
         given: 'a persistence cm handle for #cmHandleId'
-            mockPersistenceCmHandleRetrieval(additionalProperties)
-        and: 'a positive response from dmi service when it is called with the expected parameters'
+            mockPersistenceCmHandleRetrieval(dmiProperties)
+        and: 'a positive response from DMI service when it is called with the expected parameters'
             def responseFromDmi = new ResponseEntity<Object>(HttpStatus.OK)
             mockDmiRestClient.postOperationWithJsonData(
                 "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/data/ds/ncmp-datastore:${expectedDatastoreInUrl}?resourceIdentifier=${resourceIdentifier}${expectedOptionsInUrl}",
                 expectedJson, [Accept:['sample accept header']]) >> responseFromDmi
         when: 'get resource data is invoked'
             def result = objectUnderTest.getResourceDataFromDmi(cmHandleId,resourceIdentifier, options,'sample accept header', dataStore)
-        then: 'the result is the response from the dmi service'
+        then: 'the result is the response from the DMI service'
             assert result == responseFromDmi
         where: 'the following parameters are used'
-            scenario             | additionalProperties       | dataStore               | options     || expectedJson                                                 | expectedDatastoreInUrl    | expectedOptionsInUrl
-            'without properties' | []                         | PASSTHROUGH_OPERATIONAL | '(a=1,b=2)' || '{"operation":"read","cmHandleProperties":{}}'               | 'passthrough-operational' | '&options=(a=1,b=2)'
-            'null properties'    | null                       | PASSTHROUGH_OPERATIONAL | '(a=1,b=2)' || '{"operation":"read","cmHandleProperties":{}}'               | 'passthrough-operational' | '&options=(a=1,b=2)'
-            'with properties'    | [sampleAdditionalProperty] | PASSTHROUGH_OPERATIONAL | '(a=1,b=2)' || '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}' | 'passthrough-operational' | '&options=(a=1,b=2)'
-            'null options'       | [sampleAdditionalProperty] | PASSTHROUGH_OPERATIONAL | null        || '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}' | 'passthrough-operational' | ''
-            'empty options'      | [sampleAdditionalProperty] | PASSTHROUGH_OPERATIONAL | ''          || '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}' | 'passthrough-operational' | ''
-            'datastore running'  | []                         | PASSTHROUGH_RUNNING     | '(a=1,b=2)' || '{"operation":"read","cmHandleProperties":{}}'               | 'passthrough-running'     | '&options=(a=1,b=2)'
+            scenario             | dmiProperties        | dataStore               | options     || expectedJson                                                 | expectedDatastoreInUrl    | expectedOptionsInUrl
+            'without properties' | []                   | PASSTHROUGH_OPERATIONAL | '(a=1,b=2)' || '{"operation":"read","cmHandleProperties":{}}'               | 'passthrough-operational' | '&options=(a=1,b=2)'
+            'with properties'    | [dmiSampleProperty]  | PASSTHROUGH_OPERATIONAL | '(a=1,b=2)' || '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}' | 'passthrough-operational' | '&options=(a=1,b=2)'
+            'null options'       | [dmiSampleProperty]  | PASSTHROUGH_OPERATIONAL | null        || '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}' | 'passthrough-operational' | ''
+            'empty options'      | [dmiSampleProperty]  | PASSTHROUGH_OPERATIONAL | ''          || '{"operation":"read","cmHandleProperties":{"prop1":"val1"}}' | 'passthrough-operational' | ''
+            'datastore running'  | []                   | PASSTHROUGH_RUNNING     | '(a=1,b=2)' || '{"operation":"read","cmHandleProperties":{}}'               | 'passthrough-running'     | '&options=(a=1,b=2)'
     }
 
     def 'Write data for pass-through:running datastore in DMI.'() {
         given: 'a persistence cm handle for #cmHandleId'
-            mockPersistenceCmHandleRetrieval([sampleAdditionalProperty])
-        and: 'a positive response from dmi service when it is called with the expected parameters'
+            mockPersistenceCmHandleRetrieval([dmiSampleProperty])
+        and: 'a positive response from DMI service when it is called with the expected parameters'
             def expectedUrl = "${dmiServiceName}/dmi/v1/ch/${cmHandleId}/data/ds" +
                 "/ncmp-datastore:passthrough-running?resourceIdentifier=${resourceIdentifier}"
             def expectedJson = '{"operation":"' + expectedOperationInUrl + '","dataType":"some data type","data":"requestData","cmHandleProperties":{"prop1":"val1"}}'
@@ -78,7 +77,7 @@
             mockDmiRestClient.postOperationWithJsonData(expectedUrl, expectedJson, [:]) >> responseFromDmi
         when: 'write resource method is invoked'
             def result = objectUnderTest.writeResourceDataPassThroughRunningFromDmi(cmHandleId,'parent/child', operation, 'requestData', 'some data type')
-        then: 'the result is the response from the dmi service'
+        then: 'the result is the response from the DMI service'
             assert result == responseFromDmi
         where: 'the following operation is performed'
             operation || expectedOperationInUrl
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy
index 2efd6c2..bd5fe6f 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiModelOperationsSpec.groovy
@@ -49,7 +49,7 @@
     def 'Retrieving module references.'() {
         given: 'a persistence cm handle'
             mockPersistenceCmHandleRetrieval([])
-        and: 'a positive response from dmi service when it is called with the expected parameters'
+        and: 'a positive response from DMI service when it is called with the expected parameters'
             def moduleReferencesAsLisOfMaps = [[moduleName:'mod1',revision:'A'],[moduleName:'mod2',revision:'X']]
             def responseFromDmi = new ResponseEntity([schemas:moduleReferencesAsLisOfMaps], HttpStatus.OK)
             mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/modules",
@@ -63,7 +63,7 @@
     def 'Retrieving module references edge case: #scenario.'() {
         given: 'a persistence cm handle'
             mockPersistenceCmHandleRetrieval([])
-        and: 'any response from dmi service when it is called with the expected parameters'
+        and: 'any response from DMI service when it is called with the expected parameters'
             // TODO (toine): production code ignores any error code from DMI, this should be improved in future
             def responseFromDmi = new ResponseEntity(bodyAsMap, HttpStatus.NO_CONTENT)
             mockDmiRestClient.postOperationWithJsonData(*_) >> responseFromDmi
@@ -71,7 +71,7 @@
             def result = objectUnderTest.getModuleReferences(persistenceCmHandle)
         then: 'the result is empty'
             assert result == []
-        where: 'the dmi response body has the following content'
+        where: 'the DMI response body has the following content'
             scenario       | bodyAsMap
             'no modules'   | [schemas:[]]
             'modules null' | [schemas:null]
@@ -79,34 +79,33 @@
             'no body'      | null
     }
 
-    def 'Retrieving module references, additional property handling:  #scenario.'() {
+    def 'Retrieving module references, DMI property handling:  #scenario.'() {
         given: 'a persistence cm handle'
-            mockPersistenceCmHandleRetrieval(additionalPropertiesObject)
-        and: 'a positive response from dmi service when it is called with tha expected parameters'
+            mockPersistenceCmHandleRetrieval(dmiProperties)
+        and: 'a positive response from DMI service when it is called with tha expected parameters'
             def responseFromDmi = new ResponseEntity<String>(HttpStatus.OK)
             mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/modules",
                 '{"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}', [:]) >> responseFromDmi
         when: 'a get module references is called'
             def result = objectUnderTest.getModuleReferences(persistenceCmHandle)
-        then: 'the result is the response from dmi service'
+        then: 'the result is the response from DMI service'
             assert result == []
-        where: 'the following additional properties are used'
-            scenario               | additionalPropertiesObject || expectedAdditionalPropertiesInRequest
-            'with properties'      | [sampleAdditionalProperty] || '{"prop1":"val1"}'
-            'with null properties' | null                       || '{}'
-            'without properties'   | []                         || '{}'
+        where: 'the following DMI properties are used'
+            scenario               | dmiProperties       || expectedAdditionalPropertiesInRequest
+            'with properties'      | [dmiSampleProperty] || '{"prop1":"val1"}'
+            'without properties'   | []                  || '{}'
     }
 
     def 'Retrieving yang resources.'() {
         given: 'a persistence cm handle'
             mockPersistenceCmHandleRetrieval([])
-        and: 'a positive response from dmi service when it is called with tha expected parameters'
+        and: 'a positive response from DMI service when it is called with the expected parameters'
             def responseFromDmi = new ResponseEntity([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source'],
                                                       [moduleName: 'mod2', revision: 'C', yangSource: 'other yang source']], HttpStatus.OK)
             def expectedModuleReferencesInRequest = '{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}'
             mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources",
                 '{"data":{"modules":[' + expectedModuleReferencesInRequest + ']},"cmHandleProperties":{}}', [:]) >> responseFromDmi
-        when: 'get new yang resources from dmi service'
+        when: 'get new yang resources from DMI service'
             def result = objectUnderTest.getNewYangResourcesFromDmi(persistenceCmHandle, newModuleReferences)
         then: 'the result has the 2 expected yang (re)sources (order is not guaranteed)'
             assert result.size() == 2
@@ -117,43 +116,43 @@
     def 'Retrieving yang resources, edge case: scenario.'() {
         given: 'a persistence cm handle'
             mockPersistenceCmHandleRetrieval([])
-        and: 'a positive response from dmi service when it is called with tha expected parameters'
+        and: 'a positive response from DMI service when it is called with tha expected parameters'
             // TODO (toine): production code ignores any error code from DMI, this should be improved in future
             def responseFromDmi = new ResponseEntity(responseFromDmiBody, HttpStatus.NO_CONTENT)
             mockDmiRestClient.postOperationWithJsonData(*_) >> responseFromDmi
-        when: 'get new yang resources from dmi service'
+        when: 'get new yang resources from DMI service'
             def result = objectUnderTest.getNewYangResourcesFromDmi(persistenceCmHandle, newModuleReferences)
         then: 'the result is empty'
             assert result == [:]
-        where: 'the dmi response body has the following content'
+        where: 'the DMI response body has the following content'
             scenario      | responseFromDmiBody
             'empty array' | []
             'null array'  | null
     }
 
-    def 'Retrieving yang resources, additional property handling #scenario.'() {
+    def 'Retrieving yang resources, DMI property handling #scenario.'() {
         given: 'a persistence cm handle'
-            mockPersistenceCmHandleRetrieval(additionalPropertiesObject)
-        and: 'a positive response from dmi service when it is called with the expected parameters'
+            mockPersistenceCmHandleRetrieval(dmiProperties)
+        and: 'a positive response from DMI service when it is called with the expected parameters'
             def responseFromDmi = new ResponseEntity<>([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source']], HttpStatus.OK)
             mockDmiRestClient.postOperationWithJsonData("${dmiServiceName}/dmi/v1/ch/${cmHandleId}/moduleResources",
             '{"data":{"modules":[' + expectedModuleReferencesInRequest + ']},"cmHandleProperties":'+expectedAdditionalPropertiesInRequest+'}',
             [:]) >> responseFromDmi
-        when: 'get new yang resources from dmi service'
+        when: 'get new yang resources from DMI service'
             def result = objectUnderTest.getNewYangResourcesFromDmi(persistenceCmHandle, unknownModuleReferences)
-        then: 'the result is the response from dmi service'
+        then: 'the result is the response from DMI service'
             assert result == [mod1:'some yang source']
-        where: 'the following additional properties are used'
-            scenario                                | additionalPropertiesObject | unknownModuleReferences || expectedAdditionalPropertiesInRequest | expectedModuleReferencesInRequest
-            'with module references and properties' | [sampleAdditionalProperty] | newModuleReferences     || '{"prop1":"val1"}'                    | '{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}'
-            'without module references'             | [sampleAdditionalProperty] | []                      || '{"prop1":"val1"}'                    | ''
-            'without properties'                    | []                         | newModuleReferences     || '{}'                                  | '{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}'
+        where: 'the following DMI properties are used'
+            scenario                                | dmiProperties       | unknownModuleReferences || expectedAdditionalPropertiesInRequest | expectedModuleReferencesInRequest
+            'with module references and properties' | [dmiSampleProperty] | newModuleReferences     || '{"prop1":"val1"}'                    | '{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}'
+            'without module references'             | [dmiSampleProperty] | []                      || '{"prop1":"val1"}'                    | ''
+            'without properties'                    | []                  | newModuleReferences     || '{}'                                  | '{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}'
     }
 
-    def 'Retrieving yang resources from dmi with additional properties null.'() {
+    def 'Retrieving yang resources from DMI with null DMI properties.'() {
         given: 'a persistence cm handle'
             mockPersistenceCmHandleRetrieval(null)
-        when: 'a get new yang resources from dmi is called'
+        when: 'a get new yang resources from DMI is called'
             objectUnderTest.getNewYangResourcesFromDmi(persistenceCmHandle, [])
         then: 'a null pointer is thrown (we might need to address this later)'
             thrown(NullPointerException)
@@ -164,7 +163,7 @@
             mockPersistenceCmHandleRetrieval([])
         and: 'a Json processing exception occurs'
             spiedJsonObjectMapper.asJsonString(_) >> {throw (new JsonProcessingException('parsing error'))}
-        when: 'a dmi operation is executed'
+        when: 'a DMI operation is executed'
             objectUnderTest.getModuleReferences(persistenceCmHandle)
         then: 'an ncmp exception is thrown'
             def exceptionThrown = thrown(JsonProcessingException)
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy
index 4bf7dad..7b295f6 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy
@@ -1,3 +1,23 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2021-2022 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.cps.ncmp.api.impl.operations
 
 import com.fasterxml.jackson.databind.ObjectMapper
@@ -10,7 +30,7 @@
 abstract class DmiOperationsBaseSpec extends Specification {
 
     @Shared
-    def sampleAdditionalProperty = new PersistenceCmHandle.AdditionalProperty('prop1', 'val1')
+    def dmiSampleProperty = new PersistenceCmHandle.Property('prop1', 'val1')
 
     @SpringBean
     DmiRestClient mockDmiRestClient = Mock()
@@ -26,11 +46,11 @@
     def static cmHandleId = 'some cm handle'
     def static resourceIdentifier = 'parent/child'
 
-    def mockPersistenceCmHandleRetrieval(additionalProperties) {
+    def mockPersistenceCmHandleRetrieval(dmiProperties) {
         persistenceCmHandle.dmiDataServiceName = dmiServiceName
         persistenceCmHandle.dmiServiceName = dmiServiceName
-        persistenceCmHandle.additionalProperties = additionalProperties
+        persistenceCmHandle.dmiProperties = dmiProperties
         persistenceCmHandle.id = cmHandleId
-        mockCmHandlePropertiesRetriever.retrieveCmHandleDmiServiceNameAndProperties(cmHandleId) >> persistenceCmHandle
+        mockCmHandlePropertiesRetriever.retrieveCmHandleDmiServiceNameAndDmiProperties(cmHandleId) >> persistenceCmHandle
     }
 }
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/PersistenceCmHandleRetrieverSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/PersistenceCmHandleRetrieverSpec.groovy
index 3ab9266..c92234f 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/PersistenceCmHandleRetrieverSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/PersistenceCmHandleRetrieverSpec.groovy
@@ -1,3 +1,23 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021-2022 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.cps.ncmp.api.impl.operations
 
 import org.onap.cps.api.CpsDataService
@@ -19,26 +39,25 @@
     def xpath = "/dmi-registry/cm-handles[@id='some cm handle']"
 
     @Shared
-    def childDataNodesForCmHandleProperties = [new DataNode(leaves: ["name":"name1","value":"value1"]),
-                                               new DataNode(leaves: ["name":"name2","value":"value2"])]
+    def childDataNodesForCmHandleProperties = [new DataNode(xpath: "/dmi-registry/cm-handles[@id='some cm handle']/additional-properties[@name='name1']", leaves: ["name":"name1","value":"value1"]),
+                                               new DataNode(xpath: "/dmi-registry/cm-handles[@id='some cm handle']/public-properties[@name='name2']", leaves: ["name":"name2","value":"value2"])]
 
     def "Retrieve CmHandle using datanode #scenario."() {
-        given: 'the cps data service returns a data node from the dmi registry'
+        given: 'the cps data service returns a data node from the DMI registry'
             def dataNode = new DataNode(childDataNodes:childDataNodes, leaves: leaves)
             mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry', xpath, INCLUDE_ALL_DESCENDANTS) >> dataNode
         when: 'retrieving the persisted cm handle'
-            def result = objectUnderTest.retrieveCmHandleDmiServiceNameAndProperties(cmHandleId)
+            def result = objectUnderTest.retrieveCmHandleDmiServiceNameAndDmiProperties(cmHandleId)
         then: 'the result has the correct id and service names'
             result.id == cmHandleId
             result.dmiServiceName == 'common service name'
             result.dmiDataServiceName == 'data service name'
             result.dmiModelServiceName == 'model service name'
-        and: 'the expected additional properties'
-            result.additionalProperties == expectedCmHandleProperties
+        and: 'the expected DMI properties'
+            result.dmiProperties == expectedCmHandleProperties
         where: 'the following parameters are used'
-            scenario                        | childDataNodes                      || expectedCmHandleProperties
-            'without additional properties' | []                                  || []
-            'with additional properties'    | childDataNodesForCmHandleProperties || [new PersistenceCmHandle.AdditionalProperty("name1", "value1"),
-                                                                                      new PersistenceCmHandle.AdditionalProperty("name2", "value2")]
+            scenario                 | childDataNodes                      || expectedCmHandleProperties
+            'without DMI properties' | []                                  || []
+            'with DMI properties'    | childDataNodesForCmHandleProperties || [new PersistenceCmHandle.Property("name1", "value1")]
     }
 }
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/PersistenceCmHandleSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/PersistenceCmHandleSpec.groovy
index c66eaa9..49de442 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/PersistenceCmHandleSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/models/PersistenceCmHandleSpec.groovy
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2021 Nordix Foundation
+ *  Copyright (C) 2021-2022 Nordix Foundation
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
  *  SPDX-License-Identifier: Apache-2.0
  *  ============LICENSE_END=========================================================
  */
+
 package org.onap.cps.ncmp.api.models
 
 import spock.lang.Specification
@@ -26,24 +27,26 @@
 
 class PersistenceCmHandleSpec extends Specification {
 
-    def 'Setting and getting additional properties.'() {
-        given: 'a map of one property is added'
-            def objectUnderTest = new PersistenceCmHandle()
-            objectUnderTest.asAdditionalProperties([myProperty: 'some value'])
-        when: 'the additional properties are retrieved'
-            def result = objectUnderTest.getAdditionalProperties()
+    def 'Creating persistence cm handle from a cm handle.'() {
+        given: 'a cm handle with properties'
+            def cmHandle = new CmHandle()
+            cmHandle.dmiProperties = [myDmiProperty:'value1']
+            cmHandle.publicProperties = [myPublicProperty:'value2']
+        when: 'it is converted to a persistence cm handle'
+            def objectUnderTest = PersistenceCmHandle.toPersistenceCmHandle('','','', cmHandle)
         then: 'the result has the right size'
-            assert result.size() == 1
-        and: 'the property in the result has the correct name and value'
-            def actualAdditionalProperty = result.get(0)
-            def expectedAdditionalProperty = new PersistenceCmHandle.AdditionalProperty('myProperty','some value')
-            assert actualAdditionalProperty.name == expectedAdditionalProperty.name
-            assert actualAdditionalProperty.value == expectedAdditionalProperty.value
+            assert objectUnderTest.dmiProperties.size() == 1
+        and: 'the DMI property in the result has the correct name and value'
+            assert objectUnderTest.dmiProperties[0].name == 'myDmiProperty'
+            assert objectUnderTest.dmiProperties[0].value == 'value1'
+        and: 'the public property in the result has the correct name and value'
+            assert objectUnderTest.publicProperties[0].name == 'myPublicProperty'
+            assert objectUnderTest.publicProperties[0].value == 'value2'
     }
 
-    def 'Resolve dmi service name: #scenario and #requiredService service require.'() {
+    def 'Resolve DMI service name: #scenario and #requiredService service require.'() {
         given: 'a Persistence CM Handle'
-            def objectUnderTest = PersistenceCmHandle.toPersistenceCmHandle(dmiServiceName, dmiDataServiceName, dmiModelServiceName, new CmHandle('some id', null))
+            def objectUnderTest = PersistenceCmHandle.toPersistenceCmHandle(dmiServiceName, dmiDataServiceName, dmiModelServiceName, new CmHandle())
         expect:
             assert objectUnderTest.resolveDmiServiceName(requiredService) == expectedService
         where:
diff --git a/cps-parent/pom.xml b/cps-parent/pom.xml
index a51d694..2e0528e 100755
--- a/cps-parent/pom.xml
+++ b/cps-parent/pom.xml
@@ -46,6 +46,31 @@
         </sonar.coverage.jacoco.xmlReportPaths>
     </properties>
 
+    <profiles>
+        <profile>
+            <id>Windows</id>
+            <activation>
+                <os>
+                    <family>Windows</family>
+                </os>
+            </activation>
+            <properties>
+                <script.executor>python</script.executor>
+            </properties>
+        </profile>
+        <profile>
+            <id>unix</id>
+            <activation>
+                <os>
+                    <family>unix</family>
+                </os>
+            </activation>
+            <properties>
+                <script.executor>python3</script.executor>
+            </properties>
+        </profile>
+    </profiles>
+
     <dependencyManagement>
         <dependencies>
             <dependency>
@@ -377,6 +402,28 @@
                 <groupId>org.sonarsource.scanner.maven</groupId>
                 <artifactId>sonar-maven-plugin</artifactId>
             </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>exec-maven-plugin</artifactId>
+                <version>1.6.0</version>
+                <executions>
+                    <execution>
+                        <id>generate-csv</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>exec</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <executable>${script.executor}</executable>
+                    <workingDirectory>../cps-ri/src/main/resources/</workingDirectory>
+                    <arguments>
+                        <argument>yangResourceCsvGenerator.py</argument>
+                        <argument>dmi-registry@2021-12-13</argument>
+                    </arguments>
+                </configuration>
+            </plugin>
         </plugins>
     </build>
 </project>
diff --git a/cps-ri/src/main/resources/changelog/db/changes/09-loadData-dmi-registry-schema-set.yaml b/cps-ri/src/main/resources/changelog/db/changes/09-loadData-dmi-registry-schema-set.yaml
index fe2428e..723c2b9 100644
--- a/cps-ri/src/main/resources/changelog/db/changes/09-loadData-dmi-registry-schema-set.yaml
+++ b/cps-ri/src/main/resources/changelog/db/changes/09-loadData-dmi-registry-schema-set.yaml
@@ -1,5 +1,5 @@
 # ============LICENSE_START=======================================================
-# Copyright (C) 2021 Nordix Foundation.
+# Copyright (C) 2021-2022 Nordix Foundation.
 # ================================================================================
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -160,3 +160,51 @@
               delete from schema_set_yang_resources
               where schema_set_id = (select id from schema_set where name = 'ncmp-dmi-registry-model')
               and yang_resource_id = (select id from yang_resource where name = 'dmi-registry@2021-10-20.yang')
+
+  - changeSet:
+      author: cps
+      label: dmi-registry-schema-preload
+      id: 9.7
+      loadUpdateData:
+        encoding: UTF-8
+        file: 'changelog/db/changes/data/dmi//generated-csv/generated_yang_resource_dmi-registry@2021-12-13.csv'
+        onlyUpdate: 'false'
+        primaryKey: 'id'
+        quotchar: '"'
+        separator: '|'
+        tableName: 'yang_resource'
+        columns:
+          - column:
+              header:  name
+              name:  name
+              type:  STRING
+          - column:
+              header:  content
+              name: content
+              type: STRING
+          - column:
+              header:  checksum
+              name: checksum
+              type: STRING
+      rollback:
+        - sql:
+            sql: delete from yang_resource where name = 'dmi-registry@2021-12-13.yang'
+
+  - changeSet:
+      author: cps
+      label: dmi-registry-schema-preload
+      id: 9.8
+      loadUpdateData:
+        encoding: UTF-8
+        file: 'changelog/db/changes/data/dmi/schema_set_yang_resources@2021-12-13.csv'
+        quotchar: '"'
+        primaryKey: 'schema_set_id,yang_resource_id'
+        separator: '|'
+        tableName: 'schema_set_yang_resources'
+        usePreparedStatements:  true
+      rollback:
+        - sql:
+            sql: >
+              delete from schema_set_yang_resources
+              where schema_set_id = (select id from schema_set where name = 'ncmp-dmi-registry-model')
+              and yang_resource_id = (select id from yang_resource where name = 'dmi-registry@2021-12-13.yang')
\ No newline at end of file
diff --git a/cps-ri/src/main/resources/changelog/db/changes/data/dmi/generated-csv/README.md b/cps-ri/src/main/resources/changelog/db/changes/data/dmi/generated-csv/README.md
new file mode 100644
index 0000000..212acb9
--- /dev/null
+++ b/cps-ri/src/main/resources/changelog/db/changes/data/dmi/generated-csv/README.md
@@ -0,0 +1,23 @@
+<!--
+  ============LICENSE_START=======================================================
+   Copyright (C) 2022 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=========================================================
+-->
+
+##Placeholder folder for generated CSV files as part of yang models.
+
+Do not remove this folder
\ No newline at end of file
diff --git a/cps-ri/src/main/resources/changelog/db/changes/data/dmi/schema_set_yang_resources@2021-12-13.csv b/cps-ri/src/main/resources/changelog/db/changes/data/dmi/schema_set_yang_resources@2021-12-13.csv
new file mode 100644
index 0000000..3e8afdd
--- /dev/null
+++ b/cps-ri/src/main/resources/changelog/db/changes/data/dmi/schema_set_yang_resources@2021-12-13.csv
@@ -0,0 +1,3 @@
+schema_set_id|yang_resource_id
+(select id from schema_set where name='ncmp-dmi-registry-model')|(select id from yang_resource where name='dmi-registry@2021-12-13.yang')
+
diff --git a/cps-ri/src/main/resources/changelog/db/changes/data/yang-models/dmi-registry@2021-12-13.yang b/cps-ri/src/main/resources/changelog/db/changes/data/yang-models/dmi-registry@2021-12-13.yang
new file mode 100644
index 0000000..ed3559b
--- /dev/null
+++ b/cps-ri/src/main/resources/changelog/db/changes/data/yang-models/dmi-registry@2021-12-13.yang
@@ -0,0 +1,63 @@
+module dmi-registry {
+
+  yang-version 1.1;
+
+  namespace "org:onap:cps:ncmp";
+
+  prefix dmi-reg;
+
+  contact "dylan.byrne@est.tech";
+
+  revision "2021-05-20" {
+    description
+    "Initial Version";
+  }
+
+  revision "2021-10-20" {
+    description
+    "Added dmi-data-service-name & dmi-model-service-name to allow separate DMI instances for each responsibility";
+  }
+
+  revision "2021-12-13" {
+    description
+    "Added new list of public additonal properties for a Cm-Handle which are exposed to clients of the NCMP interface";
+  }
+
+  container dmi-registry {
+    list cm-handles {
+      key "id";
+      leaf id {
+        type string;
+      }
+      leaf dmi-service-name {
+        type string;
+      }
+      leaf dmi-data-service-name {
+        type string;
+      }
+      leaf dmi-model-service-name {
+        type string;
+      }
+
+      list additional-properties {
+        key "name";
+        leaf name {
+          type string;
+        }
+        leaf value {
+          type string;
+        }
+      }
+
+      list public-properties {
+        key "name";
+        leaf name {
+          type string;
+        }
+        leaf value {
+          type string;
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/cps-ri/src/main/resources/yangResourceCsvGenerator.py b/cps-ri/src/main/resources/yangResourceCsvGenerator.py
new file mode 100644
index 0000000..9a4077b
--- /dev/null
+++ b/cps-ri/src/main/resources/yangResourceCsvGenerator.py
@@ -0,0 +1,38 @@
+#  ============LICENSE_START=======================================================
+#  Copyright (C) 2022 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=========================================================
+
+
+import csv
+import hashlib
+import sys
+
+yang_source = ''
+checksum = ''
+
+for yang_source in sys.argv[1:]:
+    checksum = hashlib.sha256(str(yang_source).encode()).hexdigest()
+
+with open('changelog/db/changes/data/yang-models/' + yang_source + '.yang') as content:
+    dmiRegistry = content.read()
+
+# open the file in the write mode
+with open('changelog/db/changes/data/dmi/generated-csv/generated_yang_resource_' + yang_source + '.csv', 'w', newline='') \
+        as file:
+    writer = csv.writer(file, delimiter='|')
+    writer.writerow(["name", "content", "checksum"])
+    writer.writerow([yang_source + '.yang', dmiRegistry, checksum])
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
index 6c899c7..a302eb5 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2021 Nordix Foundation
+ *  Copyright (C) 2021-2022 Nordix Foundation
  *  Modifications Copyright (C) 2021 Pantheon.tech
  *  Modifications Copyright (C) 2021-2022 Bell Canada.
  *  ================================================================================
@@ -154,19 +154,19 @@
             'one leaf'        | '{"name": "some-name"}'
     }
 
-    def 'Update cm-handle properties' () {
-        given: 'a dmi registry model'
-            setupSchemaSetMocks('dmi-registry.yang')
+    def 'Update Bookstore node leaves' () {
+        given: 'a DMI registry model'
+            setupSchemaSetMocks('bookstore.yang')
         and: 'the expected json string'
-            def jsonData = '{"cm-handles":[{"id":"cmHandle001", "additional-properties":[{"name":"P1"}]}]}'
+            def jsonData = '{"categories":[{"code":01,"name":"Romance"}]}'
         when: 'update data method is invoked with json data and parent node xpath'
             objectUnderTest.updateNodeLeavesAndExistingDescendantLeaves(dataspaceName, anchorName,
-                '/dmi-registry', jsonData, observedTimestamp)
+                '/bookstore', jsonData, observedTimestamp)
         then: 'the persistence service method is invoked with correct parameters'
             1 * mockCpsDataPersistenceService.updateDataLeaves(dataspaceName, anchorName,
-                "/dmi-registry/cm-handles[@id='cmHandle001']", ['id': 'cmHandle001'])
+                "/bookstore/categories[@code='01']", ['name':'Romance', 'code': '01'])
         and: 'the data updated event is sent to the notification service'
-            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp, '/dmi-registry', Operation.UPDATE)
+            1 * mockNotificationService.processDataUpdatedEvent(dataspaceName, anchorName, observedTimestamp, '/bookstore', Operation.UPDATE)
     }
 
     def 'Replace data node: #scenario.'() {
diff --git a/cps-service/src/test/resources/dmi-registry.yang b/cps-service/src/test/resources/dmi-registry.yang
deleted file mode 100644
index 3c2d893..0000000
--- a/cps-service/src/test/resources/dmi-registry.yang
+++ /dev/null
@@ -1,42 +0,0 @@
-module dmi-registry {
-
-  yang-version 1.1;
-
-  namespace "org:onap:cps:ncmp";
-
-  prefix dmi-reg;
-
-  revision "2021-05-20" {
-    description
-    "Initial Version";
-  }
-
-  container dmi-registry {
-
-    list cm-handles {
-
-      key "id";
-
-      leaf id {
-        type string;
-      }
-
-      leaf dmi-service-name {
-        type string;
-      }
-
-      list additional-properties {
-
-        key "name";
-
-        leaf name {
-          type string;
-        }
-
-        leaf value {
-          type string;
-        }
-      }
-    }
-  }
-}
\ No newline at end of file
diff --git a/docs/api/swagger/ncmp/openapi-inventory.yaml b/docs/api/swagger/ncmp/openapi-inventory.yaml
index c4b6f4b..67eae41 100644
--- a/docs/api/swagger/ncmp/openapi-inventory.yaml
+++ b/docs/api/swagger/ncmp/openapi-inventory.yaml
@@ -4,12 +4,12 @@
   description: NCMP Inventory API
   version: "1.0"
 servers:
-  - url: /ncmpInventory
+- url: /ncmpInventory
 paths:
   /v1/ch:
     post:
       tags:
-        - network-cm-proxy-inventory
+      - network-cm-proxy-inventory
       summary: DMI notifies NCMP of new CM Handles
       description: "Register a DMI Plugin with any new, updated or removed CM Handles."
       operationId: updateDmiPluginRegistration
@@ -29,18 +29,30 @@
             application/json:
               schema:
                 $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 400 BAD_REQUEST
+                message: Bad request error message
+                details: Bad request error details
         "401":
           description: Unauthorized
           content:
             application/json:
               schema:
                 $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 401
+                message: Unauthorized error message
+                details: Unauthorized error details
         "403":
           description: Forbidden
           content:
             application/json:
               schema:
                 $ref: '#/components/schemas/ErrorMessage'
+              example:
+                status: 403
+                message: Forbidden error message
+                details: Forbidden error details
 components:
   schemas:
     RestDmiPluginRegistration:
@@ -48,7 +60,13 @@
       properties:
         dmiPlugin:
           type: string
-          example: onap-dmi-plugin
+          example: my-dmi-plugin
+        dmiDataPlugin:
+          type: string
+          example: my-dmi-data-plugin
+        dmiModelPlugin:
+          type: string
+          example: my-dmi-model-plugin
         createdCmHandles:
           type: array
           items:
@@ -61,21 +79,24 @@
           type: array
           items:
             type: string
+            example: "[\"my-cm-handle1\",\"my-cm-handle2\",\"my-cm-handle3\"]"
     RestCmHandle:
       required:
-        - cmHandle
+      - cmHandle
       type: object
       properties:
         cmHandle:
           type: string
-          example: cmHandle123
+          example: my-cm-handle
         cmHandleProperties:
-          $ref: '#/components/schemas/RestCmHandleAdditionalProperties'
-    RestCmHandleAdditionalProperties:
+          $ref: '#/components/schemas/RestCmHandleProperties'
+        publicCmHandleProperties:
+          $ref: '#/components/schemas/RestCmHandleProperties'
+    RestCmHandleProperties:
       type: object
       additionalProperties:
         type: string
-        example: system-001
+        example: my-property
     ErrorMessage:
       title: Error
       type: object