Object modify is added
ccbdemo_modify updated with demo code for object modify

Also some cleanup and bug fixes
---
 .../smfd/imm_modify_config/add_operation_to_ccb.cc | 105 ++++++-
 .../smfd/imm_modify_config/add_operation_to_ccb.h  |  13 +-
 src/smf/smfd/imm_modify_config/attribute.cc        | 320 ++++++++++++++++++---
 src/smf/smfd/imm_modify_config/attribute.h         |  79 +++--
 src/smf/smfd/imm_modify_config/immccb.cc           | 265 ++++++++---------
 src/smf/smfd/imm_modify_config/immccb.h            |  26 +-
 src/smf/smfd/imm_modify_demo/ccbdemo_create.cc     |   4 +-
 src/smf/smfd/imm_modify_demo/ccbdemo_delete.cc     |   4 +-
 src/smf/smfd/imm_modify_demo/ccbdemo_modify.cc     | 119 ++++++--
 src/smf/smfd/imm_om_api/common/imm_attribute.h     |   3 -
 src/smf/smfd/imm_om_api/om_ccb_object_create.h     |   3 -
 11 files changed, 669 insertions(+), 272 deletions(-)

diff --git a/src/smf/smfd/imm_modify_config/add_operation_to_ccb.cc 
b/src/smf/smfd/imm_modify_config/add_operation_to_ccb.cc
index 9db1ab1c5..6948aa89c 100644
--- a/src/smf/smfd/imm_modify_config/add_operation_to_ccb.cc
+++ b/src/smf/smfd/imm_modify_config/add_operation_to_ccb.cc
@@ -49,7 +49,7 @@ bool IsResorceAbort(const SaImmCcbHandleT& ccbHandle) {
   const SaStringT *errString = nullptr;
   SaAisErrorT ais_rc = saImmOmCcbGetErrorStrings(ccbHandle, &errString);
   if ((ais_rc == SA_AIS_OK) && (errString != nullptr)) {
-    TRACE("%s: Error string: '%s'", __FUNCTION__, errString[0]);
+    TRACE("LLDTEST %s: Error string: '%s'", __FUNCTION__, errString[0]);
     std::string err_str(errString[0]);
     if (err_str.find("IMM: Resource abort: ") != std::string::npos) {
       // Is Resource Abort
@@ -60,7 +60,7 @@ bool IsResorceAbort(const SaImmCcbHandleT& ccbHandle) {
   return rc;
 }
 
-int AddObjectCreateToCcb(const SaImmCcbHandleT& ccb_handle,
+int AddCreateToCcb(const SaImmCcbHandleT& ccb_handle,
                        const modelmodify::CreateDescriptor& create_descriptor) 
{
   TRACE_ENTER2("LLDTEST1: Parent '%s', Class '%s'",
                create_descriptor.parent_name.c_str(),
@@ -84,7 +84,7 @@ int AddObjectCreateToCcb(const SaImmCcbHandleT& ccb_handle,
   //        attribute values. This vector  must have the same scope as the
   //        creator.
   modelmodify::AttributeHandler attributes(&creator);
-  if(attributes.AddAttributes(create_descriptor) == false) {
+  if(attributes.AddAttributesForObjectCreate(create_descriptor) == false) {
     LOG_NO("LLDTEST1 %s: SetAttributeValues() Fail", __FUNCTION__);
     recovery_info = modelmodify::kFail;
   }
@@ -125,16 +125,10 @@ int AddObjectCreateToCcb(const SaImmCcbHandleT& 
ccb_handle,
   return recovery_info;
 }
 
-// Add one delete operation to a CCB
-// Recovery:  BAD HANDLE; kRestartOm
-//            FAILED OPERATION; kRestartOm or kFail
-//            BUSY; An admin operation is ongoing on an object to be deleted
-//                  We can try again to add the create
-// return: Recovery information. See immccb.h
-int AddObjectDeleteToCcb(const SaImmCcbHandleT& ccb_handle,
+int AddDeleteToCcb(const SaImmCcbHandleT& ccb_handle,
                          const modelmodify::DeleteDescriptor&
                          delete_descriptor) {
-
+  TRACE_ENTER2("LLDTEST");
   int recovery_info = modelmodify::kNotSet;
 
   // Setup an object deleter
@@ -150,13 +144,13 @@ int AddObjectDeleteToCcb(const SaImmCcbHandleT& 
ccb_handle,
         base::Sleep(base::MillisToTimespec(modelmodify::kBusyWait));
         continue;
       } else if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
-        TRACE("LLDTEST1 %s: AddObjectDeleteToCcb() Recover, %s", __FUNCTION__,
+        TRACE("LLDTEST1 %s: AddObjectDeleteToCcb() RestartOm, %s", 
__FUNCTION__,
               saf_error(ais_rc));
         recovery_info = modelmodify::kRestartOm;
         break;
-      } else if (SA_AIS_ERR_FAILED_OPERATION) {
+      } else if (ais_rc == SA_AIS_ERR_FAILED_OPERATION) {
         if (IsResorceAbort(ccb_handle)) {
-          TRACE("LLDTEST1 %s: AddObjectDeleteToCcb(), %s, kRestartOm",
+          TRACE("LLDTEST1 %s: AddObjectDeleteToCcb(), %s, RestartOm",
                 __FUNCTION__, saf_error(ais_rc));
           recovery_info = modelmodify::kRestartOm;
           break;
@@ -167,6 +161,10 @@ int AddObjectDeleteToCcb(const SaImmCcbHandleT& ccb_handle,
           recovery_info = modelmodify::kFail;
           break;
         }
+      } else {
+        // Unrecoverable Fail
+        recovery_info = modelmodify::kFail;
+        break;
       }
     }
 
@@ -181,5 +179,84 @@ int AddObjectDeleteToCcb(const SaImmCcbHandleT& ccb_handle,
     recovery_info = modelmodify::kFail;
   }
 
+  TRACE_LEAVE2("LLDTEST");
+  return recovery_info;
+}
+
+// Add one modify operation to a CCB
+// Recovery:  BAD HANDLE; kRestartOm
+//            FAILED OPERATION; kRestartOm or kFail
+//            BUSY; An admin operation is ongoing on an object to be modified
+//                  We can try again to add the modify
+// return: Recovery information. See immccb.h
+int AddModifyToCcb(const SaImmCcbHandleT& ccb_handle,
+                         const modelmodify::ModifyDescriptor&
+                         modify_descriptor) {
+  TRACE_ENTER2("LLDTEST");
+  int recovery_info = modelmodify::kNotSet;
+
+  // Setup an object modifier
+  immom::ImmOmCcbObjectModify modifier(ccb_handle,
+                                       modify_descriptor.object_name);
+
+  // One modify operation does only modify one object but may modify several
+  // attributes in that object.
+  // Add all values for all attributes that shall be modified
+  // including the object name to the modifier
+  // Note:  For each attribute the modifier needs a vector of pointers to the
+  //        modify descriptors. This vector  must have the same scope as the
+  //        modifier. Each modify descriptor contains a value and a
+  //        modification type
+  modelmodify::AttributeHandler modifications(&modifier);
+  if(modifications.AddAttributesForModification(modify_descriptor) == false) {
+    LOG_NO("LLDTEST1 %s: SetAttributeValues() Fail", __FUNCTION__);
+    recovery_info = modelmodify::kFail;
+  }
+
+  if (recovery_info == modelmodify::kNotSet) {
+    // Add the modification request to the CCB. Try gain if BUSY
+    base::Timer busy_timer(modelmodify::kBusyTimeout);
+    while (busy_timer.is_timeout() != true) {
+      if (modifier.AddObjectModifyToCcb() == false) {
+        SaAisErrorT ais_rc = modifier.ais_error();
+        if (ais_rc == SA_AIS_ERR_BUSY) {
+          base::Sleep(base::MillisToTimespec(modelmodify::kBusyWait));
+          continue;
+        } else if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
+          TRACE("LLDTEST1 %s: AddObjectModifyToCcb() RestartOm, %s", 
__FUNCTION__,
+                saf_error(ais_rc));
+          recovery_info = modelmodify::kRestartOm;
+          break;
+        } else if (ais_rc == SA_AIS_ERR_FAILED_OPERATION) {
+          if (IsResorceAbort(ccb_handle)) {
+            TRACE("LLDTEST1 %s: AddObjectModifyToCcb(), %s, RestartOm",
+                  __FUNCTION__, saf_error(ais_rc));
+            recovery_info = modelmodify::kRestartOm;
+            break;
+          } else {
+            // Unrecoverable Fail
+            LOG_NO("LLDTEST1 %s: AddObjectModifyToCcb() Fail, %s", 
__FUNCTION__,
+                   saf_error(ais_rc));
+            recovery_info = modelmodify::kFail;
+            break;
+          }
+        }
+      } else {
+        // Unrecoverable Fail
+        recovery_info = modelmodify::kFail;
+      }
+
+      // Add Modify to CCB Success
+      recovery_info = modelmodify::kContinue;
+      break;
+    }
+    if ((busy_timer.is_timeout() == true) &&
+        (recovery_info == modelmodify::kNotSet)) {
+      LOG_NO("LLDTEST %s: AddObjectModifyToCcb() Fail, BUSY timeout",
+             __FUNCTION__);
+      recovery_info = modelmodify::kFail;
+    }
+  }
   return recovery_info;
+  TRACE_LEAVE2("LLDTEST");
 }
diff --git a/src/smf/smfd/imm_modify_config/add_operation_to_ccb.h 
b/src/smf/smfd/imm_modify_config/add_operation_to_ccb.h
index 73a5e2d13..327b24894 100644
--- a/src/smf/smfd/imm_modify_config/add_operation_to_ccb.h
+++ b/src/smf/smfd/imm_modify_config/add_operation_to_ccb.h
@@ -46,7 +46,7 @@ bool IsResorceAbort(const SaImmCcbHandleT& ccbHandle);
 //            BUSY; An admin operation is ongoing on an object to be deleted
 //                  We can try again to add the create
 // return: Recovery information. See immccb.h
-int AddObjectCreateToCcb(const SaImmCcbHandleT& ccb_handle,
+int AddCreateToCcb(const SaImmCcbHandleT& ccb_handle,
                          const modelmodify::CreateDescriptor&
                          create_descriptor);
 
@@ -56,9 +56,18 @@ int AddObjectCreateToCcb(const SaImmCcbHandleT& ccb_handle,
 //            BUSY; An admin operation is ongoing on an object to be deleted
 //                  We can try again to add the create
 // return: Recovery information. See immccb.h
-int AddObjectDeleteToCcb(const SaImmCcbHandleT& ccb_handle,
+int AddDeleteToCcb(const SaImmCcbHandleT& ccb_handle,
                          const modelmodify::DeleteDescriptor&
                          delete_descriptor);
 
+// Add one modify operation to a CCB
+// Recovery:  BAD HANDLE; kRestartOm
+//            FAILED OPERATION; kRestartOm or kFail
+//            BUSY; An admin operation is ongoing on an object to be modified
+//                  We can try again to add the modify
+// return: Recovery information. See immccb.h
+int AddModifyToCcb(const SaImmCcbHandleT& ccb_handle,
+                         const modelmodify::ModifyDescriptor&
+                         modify_descriptor);
 
 #endif /* IMM_API_H */
diff --git a/src/smf/smfd/imm_modify_config/attribute.cc 
b/src/smf/smfd/imm_modify_config/attribute.cc
index 28dc6b76f..72d5e8828 100644
--- a/src/smf/smfd/imm_modify_config/attribute.cc
+++ b/src/smf/smfd/imm_modify_config/attribute.cc
@@ -99,83 +99,117 @@ static bool StringToNumericValue(const std::string& 
str_value,
   return rc;
 }
 
-bool AttributeHandler::AddAttributes(const CreateDescriptor&
+// ----------------------
+// class AttributeHandler
+// ----------------------
+
+bool AttributeHandler::AddAttributesForObjectCreate(const CreateDescriptor&
                                      create_descriptor) {
   bool rc = true;
   for (auto& attribute_descriptor : create_descriptor.attributes) {
-    rc = AddAttribute(attribute_descriptor);
+    rc = AddAttribute(attribute_descriptor, Request::kCreate);
   }
   return rc;
 }
 
-// Add one attribute to a creator. Store the attribute and
+bool AttributeHandler::AddAttributesForModification(const ModifyDescriptor&
+                                                 modify_descriptor) {
+  TRACE_ENTER2("LLDTEST");
+  bool rc = true;
+  for (auto& modification : modify_descriptor.modifications) {
+    switch (modification.modification_type) {
+      case SA_IMM_ATTR_VALUES_ADD:
+        rc = AddAttribute(modification.attribute_descriptor,
+                          Request::kModifyAdd);
+        break;
+      case SA_IMM_ATTR_VALUES_DELETE:
+        rc = AddAttribute(modification.attribute_descriptor,
+                          Request::kModifyDelete);
+        break;
+      case SA_IMM_ATTR_VALUES_REPLACE:
+        rc = AddAttribute(modification.attribute_descriptor,
+                          Request::kModifyReplace);
+        break;
+      default:
+        LOG_NO("LLDTEST %s: Invalid modification_type", __FUNCTION__);
+        rc = false;
+        break;
+    }
+  }
+
+  TRACE_LEAVE2("LLDTEST");
+  return rc;
+}
+
+// Add one attribute to a creator or a modifier. Store the attribute and
 // its values until this object goes out of scope
+// The request holds information about what to do with the attribute
 // Return false if fail
-bool AttributeHandler::AddAttribute(const AttributeDescriptor& attribute) {
+bool AttributeHandler::AddAttribute(const AttributeDescriptor& attribute,
+                                    Request request) {
+  TRACE_ENTER2("LLDTEST");
+
   bool rc = true;
   SaImmValueTypeT value_type = attribute.value_type;
   switch (value_type) {
     case SA_IMM_ATTR_SAINT32T:
-      rc = StoreNumericAttribute<SaInt32T>(attribute);
+      rc = StoreNumericAttribute<SaInt32T>(attribute, request);
       break;
 
     case SA_IMM_ATTR_SAUINT32T:
-      rc = StoreNumericAttribute<SaUint32T>(attribute);
+      rc = StoreNumericAttribute<SaUint32T>(attribute, request);
       break;
 
     case SA_IMM_ATTR_SAINT64T:
-      rc = StoreNumericAttribute<SaInt64T>(attribute);
+      rc = StoreNumericAttribute<SaInt64T>(attribute, request);
       break;
 
     case SA_IMM_ATTR_SAUINT64T:
-      rc = StoreNumericAttribute<SaUint64T>(attribute);
+      rc = StoreNumericAttribute<SaUint64T>(attribute, request);
       break;
 
     case SA_IMM_ATTR_SATIMET:
-      rc = StoreNumericAttribute<CppSaTimeT>(attribute);
+      rc = StoreNumericAttribute<CppSaTimeT>(attribute, request);
       // rc = StoreTimeTAttribute(attribute);
       break;
 
     case SA_IMM_ATTR_SAFLOATT:
-      rc = StoreNumericAttribute<SaFloatT>(attribute);
+      rc = StoreNumericAttribute<SaFloatT>(attribute, request);
       break;
 
     case SA_IMM_ATTR_SADOUBLET:
-      rc = StoreNumericAttribute<SaDoubleT>(attribute);
+      rc = StoreNumericAttribute<SaDoubleT>(attribute, request);
       break;
 
 
     case SA_IMM_ATTR_SASTRINGT: {
-      std::unique_ptr<SetAttribute> CreatorAttribute =
-          std::unique_ptr<SetAttribute>(new SetAttribute(creator_));
-      CreatorAttribute->SetAttributeValues(attribute.attribute_name,
-                                          attribute.values_as_strings);
-      set_attributesp_.push_back(std::move(CreatorAttribute));
+      StoreStringAttribute(attribute, request);
       break;
     }
 
     case SA_IMM_ATTR_SANAMET:
-      StoreSaNametAttribute(attribute);
+      StoreSaNametAttribute(attribute, request);
       break;
 
     case SA_IMM_ATTR_SAANYT:
-      StoreSaAnytAttribute(attribute);
+      StoreSaAnytAttribute(attribute, request);
       break;
 
     default:
       break;
   }
 
+  TRACE_LEAVE2("LLDTEST");
   return rc;
 }
 
 // Convert all values as a string for an attribute to numeric values.
 // Create a SetAttribute object and give that object the attribute name and its
 // numeric values. The SetAttribute object will store the attribute and give
-// the attribute name and values to the creator
+// the attribute name and values to a creator or a modifier
 // Save the SetAttribute object in a vector so that the object will be in scope
-// until "this" object goes out of scope which shall happen when the creator
-// has given the create operation to IMM
+// until "this" object goes out of scope which shall happen when the creator or
+// modifier has given the operation to IMM
 
 // All Store methods:
 // For an attribute;
@@ -185,7 +219,8 @@ bool AttributeHandler::AddAttribute(const 
AttributeDescriptor& attribute) {
 //  - Store the SetAttribute object
 template<typename T>
 bool AttributeHandler::
-StoreNumericAttribute(const AttributeDescriptor& attribute) {
+StoreNumericAttribute(const AttributeDescriptor& attribute, Request request) {
+  TRACE_ENTER2("LLDTEST");
   bool rc = true;
   SaImmValueTypeT value_type = attribute.value_type;
   T numeric_value{0};
@@ -201,17 +236,25 @@ StoreNumericAttribute(const AttributeDescriptor& 
attribute) {
     num_values.push_back(numeric_value);
   }
   if (rc == true) {
-    // Store the attribute for the creator and give it to the creator
-    std::unique_ptr<SetAttribute> CreatorAttribute =
-        std::unique_ptr<SetAttribute>(new SetAttribute(creator_));
-    CreatorAttribute->SetAttributeValues(attribute.attribute_name, num_values);
-    set_attributesp_.push_back(std::move(CreatorAttribute));
+    // Store the attribute give it to an attribute setter
+    std::unique_ptr<SetAttribute> AnAttribute;
+    if (request == Request::kCreate) {
+      AnAttribute = std::unique_ptr<SetAttribute>(new SetAttribute(creator_));
+    } else {
+      AnAttribute =
+          std::unique_ptr<SetAttribute>(new SetAttribute(modifier_, request));
+    }
+    AnAttribute->SetAttributeValues(attribute.attribute_name, num_values);
+    set_attributesp_.push_back(std::move(AnAttribute));
   }
+
+  TRACE_LEAVE2("LLDTEST");
   return rc;
 }
 
 void AttributeHandler::
-StoreSaNametAttribute(const AttributeDescriptor& attribute) {
+StoreSaNametAttribute(const AttributeDescriptor& attribute, Request request) {
+  TRACE_ENTER2("LLDTEST");
   SaNameT name_value;
   std::vector<SaNameT> name_values;
   for (auto& value_str : attribute.values_as_strings) {
@@ -219,14 +262,22 @@ StoreSaNametAttribute(const AttributeDescriptor& 
attribute) {
     name_values.push_back(name_value);
   }
 
-  std::unique_ptr<SetAttribute> CreatorAttribute =
-      std::unique_ptr<SetAttribute>(new SetAttribute(creator_));
-  CreatorAttribute->SetAttributeValues(attribute.attribute_name, name_values);
-  set_attributesp_.push_back(std::move(CreatorAttribute));
+  // Store the attribute give it to an attribute setter
+  std::unique_ptr<SetAttribute> AnAttribute;
+  if (request == Request::kCreate) {
+    AnAttribute = std::unique_ptr<SetAttribute>(new SetAttribute(creator_));
+  } else {
+    AnAttribute =
+        std::unique_ptr<SetAttribute>(new SetAttribute(modifier_, request));
+  }
+  AnAttribute->SetAttributeValues(attribute.attribute_name, name_values);
+  set_attributesp_.push_back(std::move(AnAttribute));
+  TRACE_LEAVE2("LLDTEST");
 }
 
 void AttributeHandler::
-StoreSaAnytAttribute(const AttributeDescriptor& attribute) {
+StoreSaAnytAttribute(const AttributeDescriptor& attribute, Request request) {
+  TRACE_ENTER2("LLDTEST");
   // Note: For this type it is also needed to store the buffer pointed to
   //       from the SaAnyT structure
   SaAnyT any_value;
@@ -237,12 +288,40 @@ StoreSaAnytAttribute(const AttributeDescriptor& 
attribute) {
     any_values.push_back(any_value);
   }
 
-  std::unique_ptr<SetAttribute> CreatorAttribute =
-      std::unique_ptr<SetAttribute>(new SetAttribute(creator_));
-  CreatorAttribute->SetAttributeValues(attribute.attribute_name, any_values);
-  set_attributesp_.push_back(std::move(CreatorAttribute));
+  // Store the attribute give it to an attribute setter
+  std::unique_ptr<SetAttribute> AnAttribute;
+  if (request == Request::kCreate) {
+    AnAttribute = std::unique_ptr<SetAttribute>(new SetAttribute(creator_));
+  } else {
+    AnAttribute =
+        std::unique_ptr<SetAttribute>(new SetAttribute(modifier_, request));
+  }
+  AnAttribute->SetAttributeValues(attribute.attribute_name, any_values);
+  set_attributesp_.push_back(std::move(AnAttribute));
+  TRACE_LEAVE2("LLDTEST");
+}
+
+void AttributeHandler::
+StoreStringAttribute(const AttributeDescriptor& attribute, Request request) {
+  TRACE_ENTER2("LLDTEST");
+  // Store the attribute give it to an attribute setter
+  std::unique_ptr<SetAttribute> AnAttribute;
+  if (request == Request::kCreate) {
+    AnAttribute = std::unique_ptr<SetAttribute>(new SetAttribute(creator_));
+  } else {
+    AnAttribute =
+        std::unique_ptr<SetAttribute>(new SetAttribute(modifier_, request));
+  }
+  AnAttribute->SetAttributeValues(attribute.attribute_name,
+                                  attribute.values_as_strings);
+  set_attributesp_.push_back(std::move(AnAttribute));
+  TRACE_LEAVE2("LLDTEST");
 }
 
+// ------------------
+// class SetAttribute
+// ------------------
+
 // All SetAttributeValues methods:
 // For each attribute type;
 //  - Create a Value Store object
@@ -254,6 +333,7 @@ StoreSaAnytAttribute(const AttributeDescriptor& attribute) {
 // SaAnyT
 void SetAttribute::SetAttributeValues(const std::string& name,
                           const std::vector<SaAnyT>& any_values) {
+  TRACE_ENTER2("LLDTEST");
   AnyValueStore_ =
       std::unique_ptr<AnyValueStore>(new AnyValueStore);
   for (auto& any_value : any_values) {
@@ -263,13 +343,27 @@ void SetAttribute::SetAttributeValues(const std::string& 
name,
   for (size_t i = 0; i < AnyValueStore_->Values.size(); i++) {
     AnyValueStore_->Values_p.push_back(v_ptr++);
   }
-  creator_->SetAttributeValue(name, AnyValueStore_->Values_p);
+
+  if (request_ == Request::kCreate) {
+    creator_->SetAttributeValue(name, AnyValueStore_->Values_p);
+  } else if (request_ == Request::kModifyAdd) {
+    modifier_->AddAttributeValue(name, AnyValueStore_->Values_p);
+  } else if (request_ == Request::kModifyReplace) {
+    modifier_->ReplaceAttributeValue(name, AnyValueStore_->Values_p);
+  } else if (request_ == Request::kModifyDelete) {
+    modifier_->DeleteAttributeValue(name, AnyValueStore_->Values_p);
+  } else {
+    LOG_NO("LLDTEST %s SaAnyT: Fail, The type of request is not set",
+           __FUNCTION__);
+  }
+  TRACE_LEAVE2("LLDTEST");
 }
 
 
 // SaNameT
 void SetAttribute::SetAttributeValues(const std::string& name,
                           const std::vector<SaNameT>& name_values) {
+  TRACE_ENTER2("LLDTEST");
   NameValueStore_ =
       std::unique_ptr<NameValueStore>(new NameValueStore);
   for (auto& name_value : name_values) {
@@ -279,13 +373,27 @@ void SetAttribute::SetAttributeValues(const std::string& 
name,
   for (size_t i = 0; i < NameValueStore_->Values.size(); i++) {
     NameValueStore_->Values_p.push_back(v_ptr++);
   }
-  creator_->SetAttributeValue(name, NameValueStore_->Values_p);
+
+  if (request_ == Request::kCreate) {
+    creator_->SetAttributeValue(name, NameValueStore_->Values_p);
+  } else if (request_ == Request::kModifyAdd) {
+    modifier_->AddAttributeValue(name, NameValueStore_->Values_p);
+  } else if (request_ == Request::kModifyReplace) {
+    modifier_->ReplaceAttributeValue(name, NameValueStore_->Values_p);
+  } else if (request_ == Request::kModifyDelete) {
+    modifier_->DeleteAttributeValue(name, NameValueStore_->Values_p);
+  } else {
+    LOG_NO("LLDTEST %s SaNameT: Fail, The type of request is not set",
+           __FUNCTION__);
+  }
+  TRACE_LEAVE2("LLDTEST");
 }
 
 
 // SaUint32T
 void SetAttribute::SetAttributeValues(const std::string& name,
                                 const std::vector<SaUint32T>& num_values) {
+  TRACE_ENTER2("LLDTEST");
   Uint32ValueStore_ =
       std::unique_ptr<Uint32ValueStore>(new Uint32ValueStore);
   for (auto& num_value : num_values) {
@@ -295,12 +403,33 @@ void SetAttribute::SetAttributeValues(const std::string& 
name,
   for (size_t i = 0; i < Uint32ValueStore_->Values.size(); i++) {
     Uint32ValueStore_->Values_p.push_back(v_ptr++);
   }
-  creator_->SetAttributeValue(name, Uint32ValueStore_->Values_p);
+
+  LOG_NO("LLDTEST4 %s: Set value name '%s'", __FUNCTION__, name.c_str());
+  if (request_ == Request::kCreate) {
+    creator_->SetAttributeValue(name, Uint32ValueStore_->Values_p);
+    LOG_NO("LLDTEST4 %s: Adding value %u for create", __FUNCTION__,
+           *Uint32ValueStore_->Values_p[0]);
+  } else if (request_ == Request::kModifyAdd) {
+    modifier_->AddAttributeValue(name, Uint32ValueStore_->Values_p);
+  } else if (request_ == Request::kModifyReplace) {
+    LOG_NO("LLDTEST4 %s: Adding value %u for modify 'Replace'", __FUNCTION__,
+           *Uint32ValueStore_->Values_p[0]);
+    modifier_->ReplaceAttributeValue(name, Uint32ValueStore_->Values_p);
+  } else if (request_ == Request::kModifyDelete) {
+    LOG_NO("LLDTEST4 %s: Adding value %u for modify 'Delete'", __FUNCTION__,
+           *Uint32ValueStore_->Values_p[0]);
+    modifier_->DeleteAttributeValue(name, Uint32ValueStore_->Values_p);
+  } else {
+    LOG_NO("LLDTEST %s SaUint32T: Fail, The type of request is not set",
+           __FUNCTION__);
+  }
+  TRACE_LEAVE2("LLDTEST");
 }
 
 // SaInt32T
 void SetAttribute::SetAttributeValues(const std::string& name,
                                 const std::vector<SaInt32T>& num_values) {
+  TRACE_ENTER2("LLDTEST");
   Int32ValueStore_ =
       std::unique_ptr<Int32ValueStore>(new Int32ValueStore);
   for (auto& num_value : num_values) {
@@ -310,12 +439,26 @@ void SetAttribute::SetAttributeValues(const std::string& 
name,
   for (size_t i = 0; i < Int32ValueStore_->Values.size(); i++) {
     Int32ValueStore_->Values_p.push_back(v_ptr++);
   }
-  creator_->SetAttributeValue(name, Int32ValueStore_->Values_p);
+
+  if (request_ == Request::kCreate) {
+    creator_->SetAttributeValue(name, Int32ValueStore_->Values_p);
+  } else if (request_ == Request::kModifyAdd) {
+    modifier_->AddAttributeValue(name, Int32ValueStore_->Values_p);
+  } else if (request_ == Request::kModifyReplace) {
+    modifier_->ReplaceAttributeValue(name, Int32ValueStore_->Values_p);
+  } else if (request_ == Request::kModifyDelete) {
+    modifier_->DeleteAttributeValue(name, Int32ValueStore_->Values_p);
+  } else {
+    LOG_NO("LLDTEST %s SaInt32T: Fail, The type of request is not set",
+           __FUNCTION__);
+  }
+  TRACE_LEAVE2("LLDTEST");
 }
 
 // SaUint64T
 void SetAttribute::SetAttributeValues(const std::string& name,
                                 const std::vector<SaUint64T>& num_values) {
+  TRACE_ENTER2("LLDTEST");
   Uint64ValueStore_ =
       std::unique_ptr<Uint64ValueStore>(new Uint64ValueStore);
   for (auto& num_value : num_values) {
@@ -325,11 +468,25 @@ void SetAttribute::SetAttributeValues(const std::string& 
name,
   for (size_t i = 0; i < Uint64ValueStore_->Values.size(); i++) {
     Uint64ValueStore_->Values_p.push_back(v_ptr++);
   }
-  creator_->SetAttributeValue(name, Uint64ValueStore_->Values_p);
+
+  if (request_ == Request::kCreate) {
+    creator_->SetAttributeValue(name, Uint64ValueStore_->Values_p);
+  } else if (request_ == Request::kModifyAdd) {
+    modifier_->AddAttributeValue(name, Uint64ValueStore_->Values_p);
+  } else if (request_ == Request::kModifyReplace) {
+    modifier_->ReplaceAttributeValue(name, Uint64ValueStore_->Values_p);
+  } else if (request_ == Request::kModifyDelete) {
+    modifier_->DeleteAttributeValue(name, Uint64ValueStore_->Values_p);
+  } else {
+    LOG_NO("LLDTEST %s SaUint64T: Fail, The type of request is not set",
+           __FUNCTION__);
+  }
+  TRACE_LEAVE2("LLDTEST");
 }
 
 void SetAttribute::SetAttributeValues(const std::string& name,
                                 const std::vector<SaInt64T>& num_values) {
+  TRACE_ENTER2("LLDTEST");
   Int64ValueStore_ =
       std::unique_ptr<Int64ValueStore>(new Int64ValueStore);
   for (auto& num_value : num_values) {
@@ -339,12 +496,26 @@ void SetAttribute::SetAttributeValues(const std::string& 
name,
   for (size_t i = 0; i < Int64ValueStore_->Values.size(); i++) {
     Int64ValueStore_->Values_p.push_back(v_ptr++);
   }
-  creator_->SetAttributeValue(name, Int64ValueStore_->Values_p);
+
+  if (request_ == Request::kCreate) {
+    creator_->SetAttributeValue(name, Int64ValueStore_->Values_p);
+  } else if (request_ == Request::kModifyAdd) {
+    modifier_->AddAttributeValue(name, Int64ValueStore_->Values_p);
+  } else if (request_ == Request::kModifyReplace) {
+    modifier_->ReplaceAttributeValue(name, Int64ValueStore_->Values_p);
+  } else if (request_ == Request::kModifyDelete) {
+    modifier_->DeleteAttributeValue(name, Int64ValueStore_->Values_p);
+  } else {
+    LOG_NO("LLDTEST %s SaInt64T: Fail, The type of request is not set",
+           __FUNCTION__);
+  }
+  TRACE_LEAVE2("LLDTEST");
 }
 
 // SaFloatT
 void SetAttribute::SetAttributeValues(const std::string& name,
                                 const std::vector<SaFloatT>& num_values) {
+  TRACE_ENTER2("LLDTEST");
   FloatValueStore_ =
       std::unique_ptr<FloatValueStore>(new FloatValueStore);
   for (auto& num_value : num_values) {
@@ -354,12 +525,26 @@ void SetAttribute::SetAttributeValues(const std::string& 
name,
   for (size_t i = 0; i < FloatValueStore_->Values.size(); i++) {
     FloatValueStore_->Values_p.push_back(v_ptr++);
   }
-  creator_->SetAttributeValue(name, FloatValueStore_->Values_p);
+
+  if (request_ == Request::kCreate) {
+    creator_->SetAttributeValue(name, FloatValueStore_->Values_p);
+  } else if (request_ == Request::kModifyAdd) {
+    modifier_->AddAttributeValue(name, FloatValueStore_->Values_p);
+  } else if (request_ == Request::kModifyReplace) {
+    modifier_->ReplaceAttributeValue(name, FloatValueStore_->Values_p);
+  } else if (request_ == Request::kModifyDelete) {
+    modifier_->DeleteAttributeValue(name, FloatValueStore_->Values_p);
+  } else {
+    LOG_NO("LLDTEST %s SaFloatT: Fail, The type of request is not set",
+           __FUNCTION__);
+  }
+  TRACE_LEAVE2("LLDTEST");
 }
 
 // SaDoubleT
 void SetAttribute::SetAttributeValues(const std::string& name,
                                 const std::vector<SaDoubleT>& num_values) {
+  TRACE_ENTER2("LLDTEST");
   DoubleValueStore_ =
       std::unique_ptr<DoubleValueStore>(new DoubleValueStore);
   for (auto& num_value : num_values) {
@@ -369,7 +554,20 @@ void SetAttribute::SetAttributeValues(const std::string& 
name,
   for (size_t i = 0; i < DoubleValueStore_->Values.size(); i++) {
     DoubleValueStore_->Values_p.push_back(v_ptr++);
   }
-  creator_->SetAttributeValue(name, DoubleValueStore_->Values_p);
+
+  if (request_ == Request::kCreate) {
+    creator_->SetAttributeValue(name, DoubleValueStore_->Values_p);
+  } else if (request_ == Request::kModifyAdd) {
+    modifier_->AddAttributeValue(name, DoubleValueStore_->Values_p);
+  } else if (request_ == Request::kModifyReplace) {
+    modifier_->ReplaceAttributeValue(name, DoubleValueStore_->Values_p);
+  } else if (request_ == Request::kModifyDelete) {
+    modifier_->DeleteAttributeValue(name, DoubleValueStore_->Values_p);
+  } else {
+    LOG_NO("LLDTEST %s SaDoubleT: Fail, The type of request is not set",
+           __FUNCTION__);
+  }
+  TRACE_LEAVE2("LLDTEST");
 }
 
 // SaTimeT
@@ -378,6 +576,7 @@ void SetAttribute::SetAttributeValues(const std::string& 
name,
 // given to the creator API (see SetAttributeValue and TimeValueStore)
 void SetAttribute::SetAttributeValues(const std::string& name,
                                 const std::vector<CppSaTimeT>& time_values) {
+  TRACE_ENTER2("LLDTEST");
   TimeValueStore_ =
       std::unique_ptr<TimeValueStore>(new TimeValueStore);
   for (auto& num_value : time_values) {
@@ -387,11 +586,25 @@ void SetAttribute::SetAttributeValues(const std::string& 
name,
   for (size_t i = 0; i < TimeValueStore_->Values.size(); i++) {
     TimeValueStore_->Values_p.push_back(v_ptr++);
   }
-  creator_->SetAttributeValue(name, TimeValueStore_->Values_p);
+
+  if (request_ == Request::kCreate) {
+    creator_->SetAttributeValue(name, TimeValueStore_->Values_p);
+  } else if (request_ == Request::kModifyAdd) {
+    modifier_->AddAttributeValue(name, TimeValueStore_->Values_p);
+  } else if (request_ == Request::kModifyReplace) {
+    modifier_->ReplaceAttributeValue(name, TimeValueStore_->Values_p);
+  } else if (request_ == Request::kModifyDelete) {
+    modifier_->DeleteAttributeValue(name, TimeValueStore_->Values_p);
+  } else {
+    LOG_NO("LLDTEST %s CppSaTimeT: Fail, The type of request is not set",
+           __FUNCTION__);
+  }
+  TRACE_LEAVE2("LLDTEST");
 }
 
 void SetAttribute::SetAttributeValues(const std::string& name,
                                 const std::vector<std::string>& str_values) {
+  TRACE_ENTER2("LLDTEST");
   StringValueStore_ =
       std::unique_ptr<StringValueStore>(new StringValueStore);
   for (auto& str_value : str_values) {
@@ -401,5 +614,18 @@ void SetAttribute::SetAttributeValues(const std::string& 
name,
   for (size_t i = 0; i < StringValueStore_->Values.size(); i++) {
     StringValueStore_->Values_p.push_back(v_ptr++);
   }
-  creator_->SetAttributeValue(name, StringValueStore_->Values_p);
+
+  if (request_ == Request::kCreate) {
+    creator_->SetAttributeValue(name, StringValueStore_->Values_p);
+  } else if (request_ == Request::kModifyAdd) {
+    modifier_->AddAttributeValue(name, StringValueStore_->Values_p);
+  } else if (request_ == Request::kModifyReplace) {
+    modifier_->ReplaceAttributeValue(name, StringValueStore_->Values_p);
+  } else if (request_ == Request::kModifyDelete) {
+    modifier_->DeleteAttributeValue(name, StringValueStore_->Values_p);
+  } else {
+    LOG_NO("LLDTEST %s string: Fail, The type of request is not set",
+           __FUNCTION__);
+  }
+  TRACE_LEAVE2("LLDTEST");
 }
diff --git a/src/smf/smfd/imm_modify_config/attribute.h 
b/src/smf/smfd/imm_modify_config/attribute.h
index 41112d1d6..7cb0e316c 100644
--- a/src/smf/smfd/imm_modify_config/attribute.h
+++ b/src/smf/smfd/imm_modify_config/attribute.h
@@ -122,26 +122,34 @@ struct AnyValueStore {
   std::vector<SaAnyT*> Values_p;
 };
 
+// Attributes are used with different types of operations
+enum class Request {
+  kNotSet,
+  kCreate,
+  kModifyAdd,
+  kModifyReplace,
+  kModifyDelete
+};
+
 // Adds one attribute to a creator
 // Used by class Attribute. Class SAttribute must see to that all objects of
 // this class does not go out of scope until an object of class Attribute goes
 // out of scope
 class SetAttribute {
  public:
-  explicit SetAttribute(immom::ImmOmCcbObjectCreate* creator)
-    : Uint32ValueStore_(nullptr),
-      Int32ValueStore_(nullptr),
-      Int64ValueStore_(nullptr),
-      Uint64ValueStore_(nullptr),
-      TimeValueStore_(nullptr),
-      FloatValueStore_(nullptr),
-      DoubleValueStore_(nullptr),
-      StringValueStore_(nullptr),
-      NameValueStore_(nullptr),
-      AnyValueStore_(nullptr),
-      creator_(creator) {}
+  explicit SetAttribute(immom::ImmOmCcbObjectCreate* creator) : SetAttribute()
+  {
+    creator_ = creator;
+    request_ = Request::kCreate;
+  }
+  explicit SetAttribute(immom::ImmOmCcbObjectModify* modifier, Request request)
+      : SetAttribute()
+  {
+    modifier_ = modifier;
+    request_ = request;
+  }
 
-  // Store one attribute of a given type and add it to a creator
+  // Store one attribute of a given type and add it to a creator or a modifier
   // The values are stored in a vector and another vector with pointers to the
   // values is created. It is the pointer vector that is the in parameter for
   // the creator
@@ -171,6 +179,22 @@ class SetAttribute {
                           const std::vector<SaAnyT>& any_values);
 
  private:
+  // Constructor for initializing variables only
+  SetAttribute()
+    : Uint32ValueStore_(nullptr),
+      Int32ValueStore_(nullptr),
+      Int64ValueStore_(nullptr),
+      Uint64ValueStore_(nullptr),
+      TimeValueStore_(nullptr),
+      FloatValueStore_(nullptr),
+      DoubleValueStore_(nullptr),
+      StringValueStore_(nullptr),
+      NameValueStore_(nullptr),
+      AnyValueStore_(nullptr),
+      creator_(nullptr),
+      modifier_(nullptr),
+      request_(Request::kNotSet) {}
+
   // Numeric
   std::unique_ptr<Uint32ValueStore> Uint32ValueStore_;
   std::unique_ptr<Int32ValueStore> Int32ValueStore_;
@@ -189,6 +213,8 @@ class SetAttribute {
 
 
   immom::ImmOmCcbObjectCreate* creator_;
+  immom::ImmOmCcbObjectModify* modifier_;
+  Request request_;
 
   DELETE_COPY_AND_MOVE_OPERATORS(SetAttribute);
 };
@@ -210,23 +236,38 @@ class SetAttribute {
 class AttributeHandler {
  public:
   explicit AttributeHandler(immom::ImmOmCcbObjectCreate* creator)
-    : creator_(creator) {}
+    : creator_(creator), modifier_(nullptr) {}
+  explicit AttributeHandler(immom::ImmOmCcbObjectModify* modifier)
+    : creator_(nullptr), modifier_(modifier) {}
 
   // Add all attributes in a create descriptor to a creator
-  bool AddAttributes(const CreateDescriptor& create_descriptor);
+  bool AddAttributesForObjectCreate(const CreateDescriptor& create_descriptor);
+
+  // Add all attributes in a modify descriptor
+  // Note that each attribute has an AttributeModifyDescriptor which contains
+  // Information about modification type an an AttributeDescriptor
+  bool AddAttributesForModification(const ModifyDescriptor& modify_descriptor);
 
  private:
-  bool AddAttribute(const AttributeDescriptor& attribute);
+  bool AddAttribute(const AttributeDescriptor& attribute, Request request);
 
   template<typename T>
-  bool StoreNumericAttribute(const AttributeDescriptor& attribute);
+  bool StoreNumericAttribute(const AttributeDescriptor& attribute,
+                             Request request);
+
+  void StoreSaNametAttribute(const AttributeDescriptor& attribute,
+                             Request request);
 
-  void StoreSaNametAttribute(const AttributeDescriptor& attribute);
+  void StoreSaAnytAttribute(const AttributeDescriptor& attribute,
+                            Request request);
 
-  void StoreSaAnytAttribute(const AttributeDescriptor& attribute);
+  void StoreStringAttribute(const AttributeDescriptor& attribute,
+                            Request request);
 
   std::vector<std::unique_ptr<SetAttribute>> set_attributesp_;
   immom::ImmOmCcbObjectCreate* creator_;
+  immom::ImmOmCcbObjectModify* modifier_;
+  SaImmAttrModificationTypeT modification_type_;
 
   DELETE_COPY_AND_MOVE_OPERATORS(AttributeHandler);
 };
diff --git a/src/smf/smfd/imm_modify_config/immccb.cc 
b/src/smf/smfd/imm_modify_config/immccb.cc
index 9524aecb8..e52d6b9e6 100644
--- a/src/smf/smfd/imm_modify_config/immccb.cc
+++ b/src/smf/smfd/imm_modify_config/immccb.cc
@@ -59,9 +59,9 @@ using namespace modelmodify;
 //-------------------------
 
 // The global instance number
-std::atomic<unsigned int> ObjectModification::next_instance_number_{1};
+std::atomic<unsigned int> ModelModification::next_instance_number_{1};
 
-ObjectModification::ObjectModification()
+ModelModification::ModelModification()
     : imm_om_handle_(nullptr),
       imm_ccb_handle_(nullptr),
       imm_ao_handle_(nullptr),
@@ -75,14 +75,14 @@ ObjectModification::ObjectModification()
         std::to_string(instance_number_);
   }
 
-ObjectModification::~ObjectModification() {
+ModelModification::~ModelModification() {
   // If an OM handle exists, cleanup the CCB handling by finalizing the handle
   // Note that releaseOwnershipFinalize must be set when creating an OM admin
   // owner handle so that admin ownership is released
   FinalizeHandles();
 }
 
-bool ObjectModification::DoModification(CcbDescriptor modifications) {
+bool ModelModification::DoModelModification(CcbDescriptor modifications) {
   TRACE_ENTER2("LLDTEST");
   bool return_status = false;
   int recovery_info = kNotSet;
@@ -117,8 +117,16 @@ bool ObjectModification::DoModification(CcbDescriptor 
modifications) {
       continue;
     }
 
-    // TODO(Lennart)
     // AddModifications. Request modifications of exiting IMM objects
+    recovery_info = AddModifies(modifications.modify_descriptors);
+    if (recovery_info == kFail) {
+      LOG_NO("LLDTEST %s: AddModifies() Fail", __FUNCTION__);
+      break;
+    } else if (recovery_info == kRestartOm) {
+      TRACE("LLDTEST %s: AddModifies() Restart", __FUNCTION__);
+      LOG_NO("LLDTEST6 %s: AddModifies() Restart", __FUNCTION__);
+      continue;
+    }
 
     // AddDeletes. Delete IMM objects
     recovery_info = AddDeletes(modifications.delete_descriptors);
@@ -136,7 +144,7 @@ bool ObjectModification::DoModification(CcbDescriptor 
modifications) {
       LOG_NO("LLDTEST %s: ApplyModifications() Fail", __FUNCTION__);
       break;
     } else if (recovery_info == kRestartOm) {
-      TRACE("LLDTEST %s: ApplyModifications() Retry", __FUNCTION__);
+      TRACE("LLDTEST %s: ApplyModifications() Restart", __FUNCTION__);
       continue;
     }
 
@@ -160,7 +168,7 @@ bool ObjectModification::DoModification(CcbDescriptor 
modifications) {
 // Note1: Handle objects are created and private handle pointers are filled in
 // Note2: No admin ownership is set here
 // Return:  Recovery information. See Private constants
-int ObjectModification::CreateHandles() {
+int ModelModification::CreateHandles() {
   TRACE_ENTER2("LLDTEST");
   int recovery_info = kNotSet;
 
@@ -201,7 +209,7 @@ int ObjectModification::CreateHandles() {
 // Recovery: No AIS return code except TRY AGAIN is valid for retry
 // Output:  A valid OM handle. An OM handle object is created
 // Return:  Recovery information. See Private constants
-int ObjectModification::CreateObjectManager() {
+int ModelModification::CreateObjectManager() {
   TRACE_ENTER2("LLDTEST");
   int recovery_info = kNotSet;
   if (imm_om_handle_ == nullptr) {
@@ -215,10 +223,6 @@ int ObjectModification::CreateObjectManager() {
   }
 
   bool return_state = imm_om_handle_->InitializeHandle();
-  // TODO(Lennart) This is an example of how to fill in error info. May be
-  // done in other places where IMM APIs are used, but do we really need this?
-  error_info_.ais_error = imm_om_handle_->ais_error();
-  error_info_.function_name = "saImmOmInitialize";
   if (return_state == false) {
     // No recovery is possible
     LOG_NO("LLDTEST %s: OM-handle, InitializeHandle(), Fail", __FUNCTION__);
@@ -240,7 +244,7 @@ int ObjectModification::CreateObjectManager() {
 // Output:  A valid Admin Owner (AO) handle. An admin owner handle object and
 //          an Admin Owner Set object is created
 // Return:  Recovery information. See Private constants
-int ObjectModification::CreateAdminOwner() {
+int ModelModification::CreateAdminOwner() {
   TRACE_ENTER2("LLDTEST");
   int recovery_info = kNotSet;
   if (imm_ao_handle_ == nullptr) {
@@ -277,7 +281,7 @@ int ObjectModification::CreateAdminOwner() {
 // Recovery:  BAD HANDLE; Restart CCB handling
 // Output:  A valid CCB handle. A CCB handle object is created
 // Return:  Recovery information. See Private constants
-int ObjectModification::CreateCcb() {
+int ModelModification::CreateCcb() {
   TRACE_ENTER2("LLDTEST");
   int recovery_info = kNotSet;
   if (imm_ccb_handle_ == nullptr) {
@@ -305,7 +309,7 @@ int ObjectModification::CreateCcb() {
 }
 
 // Finalize all handles. Return code does not matter here
-void ObjectModification::FinalizeHandles() {
+void ModelModification::FinalizeHandles() {
   TRACE_ENTER2("LLDTEST");
   if (imm_om_handle_ != nullptr) {
     // If an OM handle object exists the OM handle owned by the object shall be
@@ -332,7 +336,7 @@ void ObjectModification::FinalizeHandles() {
 //          a cluster wide resource. Others trying to become owner of the
 //          object(s) will fail with EXIST
 // Return:  Recovery information. See Private constants
-int ObjectModification::AdminOwnerSet(std::vector<std::string>& objects,
+int ModelModification::AdminOwnerSet(std::vector<std::string>& objects,
                                       SaImmScopeT scope) {
   TRACE_ENTER2("LLDTEST2");
 
@@ -349,10 +353,7 @@ int 
ObjectModification::AdminOwnerSet(std::vector<std::string>& objects,
   }
 
   // Set objects to become admin owner of
-  TRACE("LLDTEST2 %s: Becoming admin owner of the following objects:",
-        __FUNCTION__);
   for (auto& object : objects) {
-    TRACE("LLDTEST2 %s: Object '%s'", __FUNCTION__, object.c_str());
     if (object.empty()) {
       // Do not add empty strings (IMM root)
       continue;
@@ -377,7 +378,8 @@ int 
ObjectModification::AdminOwnerSet(std::vector<std::string>& objects,
         base::Sleep(base::MillisToTimespec(kExistWait));
         continue;
       } else if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
-        TRACE("LLDTEST2 %s: SetAdminOwner() Restart", __FUNCTION__);
+        TRACE("LLDTEST2 %s: SetAdminOwner() Restart, %s", __FUNCTION__,
+              saf_error(ais_rc));
         recovery_info = kRestartOm;
         break;
       } else {
@@ -401,90 +403,24 @@ int 
ObjectModification::AdminOwnerSet(std::vector<std::string>& objects,
   return recovery_info;
 }
 
-#if 0 // TODO(Lennart) Not used so it can be removed
-// Release admin ownership that was previously set using AdminOwnerSet(...)
-// Recovery:  BAD_HANDLE; Nothing to do. In this case admin ownership is
-//                        released
-//            BUSY;       An admin operation is ongoing on one of the objects
-//                        belonging to this admin owner. We can try again
-int ObjectModification::AdminOwnerRelease(void) {
-  TRACE_ENTER2("LLDTEST21");
-
-  // TODO(Lennart) Remove this function. It is never needed. The admin owner
-  // shall not be released until the CCB is applied. The admin owner will be
-  // released when the om handle is finalized (note that the
-  // releaseOwnershipOnFinalize flag must be set to true. This is done by
-  // default when the admin owner is created)
-  // For now this function is dummy
-  return kContinue;
-
-
-  if (imm_ao_owner_set_ == nullptr) {
-    // Should never happen
-    LOG_ER("LLDTEST21 %s: No admin owner handle is created", __FUNCTION__);
-    return kFail;
-  }
-
-  // Release this Admin Owner
-  // An object is a cluster global resource. It is not possible to release
-  // admin ownership if there is an ongoing admin operation where this owner is
-  // used. Wait a reasonable time for the resource to be released.
-  // Note:  This should in practice not be possible in this context since this
-  //        admin owner is "owned" and used by this class only
-  base::Timer busy_timer(kBusyTimeout);
-  SaAisErrorT ais_rc = SA_AIS_OK;
-  int recovery_info = kNotSet;
-
-  while (busy_timer.is_timeout() == false) {
-    if (imm_ao_owner_set_->ReleaseAdminOwner() == false) {
-      ais_rc = imm_ao_owner_set_->ais_error();
-      if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
-        // This Admin owner is already released, no error
-        recovery_info = kContinue;
-        break;
-      } else if (ais_rc == SA_AIS_ERR_BUSY) {
-        TRACE("LLDTEST21 %s: SA_AIS_ERR_BUSY", __FUNCTION__);
-        base::Sleep(base::MillisToTimespec(kBusyWait));
-        continue;
-      } else {
-        LOG_NO("LLDTEST21 %s: ReleaseAdminOwner() Fail, %s", __FUNCTION__,
-               saf_error(ais_rc));
-        recovery_info = kFail;
-        break;
-      }
-    }
-
-    recovery_info = kContinue;
-    break;
-  }
-  if ((busy_timer.is_timeout() == true) && (recovery_info == kNotSet)) {
-    LOG_NO("LLDTEST21 %s: ReleaseAdminOwner() Fail, BUSY timeout",
-           __FUNCTION__);
-    recovery_info = kFail;
-  }
-
-  imm_ao_owner_set_->ClearObjectNames();
-  TRACE_LEAVE2("LLDTEST21");
-  return recovery_info;
-}
-#endif
-
 // Add create requests for all objects to be created
 // Set admin ownership for parent to all objects to be created with scope
 // SA_IMM_ONE.
 // Add all create operations to the CCB
-// Note1: We have to be owner of the parent
+// Note1: We have to be owner of the parent(s)
 // Note2: It is not a problem to set admin ownership of an object that already
 //        has an admin owner if the same admin owner name is used, meaning that
 //        this is not needed to check
 // Recovery:  BAD HANDLE; Restart CCB handling
 //            FAILED OPERATION; Restart CCB handling
 // Return:  Recovery information
-int ObjectModification::AddCreates(std::vector<CreateDescriptor>&
+int ModelModification::AddCreates(std::vector<CreateDescriptor>&
       create_descriptors) {
   TRACE_ENTER2("LLDTEST");
   int recovery_info = kNotSet;
 
+  // TODO(Lennart) The code below for setting admin owner is the same (almost)
+  // for all configuration operations (redundant). Fix
   // Do this for all create descriptors
   for (auto& create_descriptor : create_descriptors) {
     if (create_descriptor.parent_name.empty() == false) {
@@ -504,38 +440,20 @@ int 
ObjectModification::AddCreates(std::vector<CreateDescriptor>&
 
     // Add the object create request to the ccb:
     recovery_info = AddCreate(create_descriptor);
-    if (recovery_info != kContinue) {
-      TRACE("LLDTEST %s: AddCreate() Recovery Info %s",
-             __FUNCTION__, RecoveryTxt(recovery_info));
-    }
-
-#if 0 // TODO(Lennart) Shall be done after CCB Apply and is done when
-      // OM Finalize is done so this code can be removed
-    // Cleanup admin ownership
-    // We shall always try to do this if an admin owner was set
-    int release_recovery_info = AdminOwnerRelease();
-    if (recovery_info != kContinue) {
-      // If the previous AddCreate was not successful then recovery info from
-      // AdminOwnerRelease is not relevant. We must break based on AddCreate
-      // recovery info.
-      break;
-    }
-
-    if (release_recovery_info == kFail) {
-      LOG_NO("LLDTEST %s: AdminOwnerRelease() Fail", __FUNCTION__);
+    if (recovery_info == kFail) {
+      LOG_NO("LLDTEST %s: AddCreate() Fail", __FUNCTION__);
       break;
-    } else if (release_recovery_info == kRestartOm) {
-      TRACE("LLDTEST %s: AdminOwnerRelease() Restart", __FUNCTION__);
+    } else if (recovery_info == kRestartOm) {
+      TRACE("LLDTEST %s: AddCreate() Restart", __FUNCTION__);
       break;
     }
-#endif
   } // For all create descriptors
 
   if (recovery_info == kNotSet) {
-    // All creates are added, no recovery needed
+    // No creates are added, no recovery needed
     recovery_info = kContinue;
   }
-  TRACE_LEAVE2("LLDTEST, recovery_info = %s", RecoveryTxt(recovery_info));
+  TRACE_LEAVE2("LLDTEST");
   return recovery_info;
 }
 
@@ -544,12 +462,11 @@ int 
ObjectModification::AddCreates(std::vector<CreateDescriptor>&
 //  Add all attributes
 //  Add the create request to the ccb
 // Return: Recovery information
-int ObjectModification::AddCreate(CreateDescriptor& create_descriptor) {
+int ModelModification::AddCreate(CreateDescriptor& create_descriptor) {
   TRACE_ENTER2("LLDTEST");
-  int recovery_info = kNotSet;
-  SaImmCcbHandleT ccb_handle = imm_ccb_handle_->GetHandle();
 
-  recovery_info = AddObjectCreateToCcb(ccb_handle, create_descriptor);
+  SaImmCcbHandleT ccb_handle = imm_ccb_handle_->GetHandle();
+  int recovery_info = AddCreateToCcb(ccb_handle, create_descriptor);
 
   TRACE_LEAVE2("LLDTEST");
   return recovery_info;
@@ -558,14 +475,14 @@ int ObjectModification::AddCreate(CreateDescriptor& 
create_descriptor) {
 // Add delete requests for all objects to be deleted
 // Set admin ownership for objects to be deleted with scope SA_IMM_SUBTREE.
 // Add all delete operations to the CCB
-// Note1: We have to be owner of the object and the sub tree
+// Note1: We have to be owner of the object(s) and the sub tree
 // Note2: It is not a problem to set admin ownership of an object that already
 //        has an admin owner if the same admin owner name is used, meaning that
 //        this is not needed to check
 // Recovery:  BAD HANDLE; Restart CCB handling
 //            FAILED OPERATION; Restart CCB handling if resource abort
 // Return:  Recovery information
-int ObjectModification::AddDeletes(std::vector<DeleteDescriptor>&
+int ModelModification::AddDeletes(std::vector<DeleteDescriptor>&
       delete_descriptors) {
   TRACE_ENTER2("LLDTEST");
   int recovery_info = kNotSet;
@@ -585,46 +502,28 @@ int 
ObjectModification::AddDeletes(std::vector<DeleteDescriptor>&
         break;
       }
     } else {
-      LOG_NO("LLDTEST %s: AddDeletes() Fail, No object to delete",
+      LOG_NO("LLDTEST %s: AddDeletes() Fail, Object name is missing",
              __FUNCTION__);
       recovery_info = kFail;
+      break;
     }
 
     // Add the object delete request to the ccb:
     recovery_info = AddDelete(delete_descriptor);
-    if (recovery_info != kContinue) {
-      TRACE("LLDTEST %s: AddDelete() Recovery Info %s",
-             __FUNCTION__, RecoveryTxt(recovery_info));
-    }
-
-#if 0 // TODO(Lennart) Shall be done after CCB Apply and is done when
-      // OM Finalize is done so this code can be removed
-    // Cleanup admin ownership
-    // Cleanup admin ownership
-    // We shall always try to do this if an admin owner was set
-    int release_recovery_info = AdminOwnerRelease();
-    if (recovery_info != kContinue) {
-      // If the previous AddDelete was not successful then recovery info from
-      // AdminOwnerRelease is not relevant. We must break based on AddDelete
-      // recovery info.
-      break;
-    }
-
-    if (release_recovery_info == kFail) {
-      LOG_NO("LLDTEST %s: AdminOwnerRelease() Fail", __FUNCTION__);
+    if (recovery_info == kFail) {
+      LOG_NO("LLDTEST %s: AddDelete() Fail", __FUNCTION__);
       break;
-    } else if (release_recovery_info == kRestartOm) {
-      TRACE("LLDTEST %s: AdminOwnerRelease() Restart", __FUNCTION__);
+    } else if (recovery_info == kRestartOm) {
+      TRACE("LLDTEST %s: AddDelete() Restart", __FUNCTION__);
       break;
     }
-#endif
   } // For all delete descriptors
 
    if (recovery_info == kNotSet) {
-    // All deletes are added, no recovery needed
+    // No deletes are added, no recovery needed
     recovery_info = kContinue;
   }
-  TRACE_LEAVE2("LLDTEST, recovery_info = %s", RecoveryTxt(recovery_info));
+  TRACE_LEAVE2("LLDTEST");
   return recovery_info;
 }
 
@@ -632,25 +531,91 @@ int 
ObjectModification::AddDeletes(std::vector<DeleteDescriptor>&
 //  Set object name
 //  Add the delete request to the ccb
 // Return: Recovery information
-int ObjectModification::AddDelete(DeleteDescriptor& delete_descriptor) {
+int ModelModification::AddDelete(DeleteDescriptor& delete_descriptor) {
   TRACE_ENTER2("LLDTEST");
-  int recovery_info = kNotSet;
+
   SaImmCcbHandleT ccb_handle = imm_ccb_handle_->GetHandle();
+  int recovery_info = AddDeleteToCcb(ccb_handle, delete_descriptor);
 
-  recovery_info = AddObjectDeleteToCcb(ccb_handle, delete_descriptor);
+  TRACE_LEAVE2("LLDTEST");
+  return recovery_info;
+}
 
+// Add modify requests for all objects to be modified
+// Set admin ownership for all objects to be modified with scope
+// SA_IMM_ONE.
+// Add all modify operations to the CCB
+// Note1: We have to be owner of the object(s)
+// Note2: It is not a problem to set admin ownership of an object that already
+//        has an admin owner if the same admin owner name is used, meaning that
+//        this is not needed to check
+// Recovery:  BAD HANDLE; Restart CCB handling
+//            FAILED OPERATION; Restart CCB handling
+// Return:  Recovery information
+int ModelModification::AddModifies(std::vector<ModifyDescriptor>&
+                                    modify_descriptors) {
+  TRACE_ENTER2("LLDTEST");
+  int recovery_info = kNotSet;
 
+  // Do this for all modify descriptors
+  for (auto& modify_descriptor : modify_descriptors) {
+    if (modify_descriptor.object_name.empty() == false) {
+      // Become admin owner of object if there is an object. If not Fail
+      std::vector<std::string> imm_objects;
+      imm_objects.push_back(modify_descriptor.object_name);
+      recovery_info = AdminOwnerSet(imm_objects, SA_IMM_ONE);
+      if (recovery_info == kFail) {
+        LOG_NO("LLDTEST %s: AdminOwnerSet() Fail", __FUNCTION__);
+        break;
+      } else if (recovery_info == kRestartOm) {
+        TRACE("LLDTEST %s: AdminOwnerSet() Restart", __FUNCTION__);
+        break;
+      }
+    } else {
+      LOG_NO("LLDTEST %s: AddModifies() Fail, Object name is missing",
+             __FUNCTION__);
+      recovery_info = kFail;
+      break;
+    }
+
+    // Add the object modify request to the ccb:
+    recovery_info = AddModify(modify_descriptor);
+    if (recovery_info == kFail) {
+      LOG_NO("LLDTEST %s: AddModify() Fail", __FUNCTION__);
+      break;
+    } else if (recovery_info == kRestartOm) {
+      TRACE("LLDTEST %s: AddModify() Restart", __FUNCTION__);
+      break;
+    }
+  } // For all modify descriptors
+
+   if (recovery_info == kNotSet) {
+    // All deletes are added, no recovery needed
+    recovery_info = kContinue;
+  }
   TRACE_LEAVE2("LLDTEST");
   return recovery_info;
 }
 
+// Add one modify descriptor to the ccb
+//  Set object name
+//  Add the modify request to the ccb.
+//    The modify request can only be for one object but may contain
+//    modifications for several attributes
+int ModelModification::AddModify(ModifyDescriptor& modify_descriptor) {
+  TRACE_ENTER2("LLDTEST");
 
+  SaImmCcbHandleT ccb_handle = imm_ccb_handle_->GetHandle();
+  int recovery_info = AddModifyToCcb(ccb_handle, modify_descriptor);
 
+  TRACE_LEAVE2("LLDTEST");
+  return recovery_info;
+}
 
 // Apply the CCB. Based on a valid CCB handle
 // Recovery:  BAD HANDLE; Restart CCBhandling
 //            FAILED OPERATION; Restart CCBhandling
-int ObjectModification::ApplyModifications() {
+int ModelModification::ApplyModifications() {
   TRACE_ENTER2("LLDTEST");
   int recovery_info = kNotSet;
 
diff --git a/src/smf/smfd/imm_modify_config/immccb.h 
b/src/smf/smfd/imm_modify_config/immccb.h
index e633fd1bc..6fc71eee4 100644
--- a/src/smf/smfd/imm_modify_config/immccb.h
+++ b/src/smf/smfd/imm_modify_config/immccb.h
@@ -158,7 +158,7 @@ struct AttributeModifyDescriptor {
   // Type of modification
   SaImmAttrModificationTypeT modification_type;
   // The attribute to be modified and the new value(s)
-  AttributeDescriptor attribute;
+  AttributeDescriptor attribute_descriptor;
 };
 
 
@@ -212,7 +212,7 @@ struct ModifyDescriptor {
   // Full DN of the object to be modified
   std::string object_name;
   std::vector<AttributeModifyDescriptor> modifications;
-  void AddModification(AttributeModifyDescriptor one_modification) {
+  void AddAttributeModification(AttributeModifyDescriptor one_modification) {
     modifications.push_back(one_modification);
   }
 };
@@ -275,13 +275,13 @@ const uint64_t kExistWait = 2000; // 2 sec
 inline static const char* RecoveryTxt(int recovery_info) {
   switch (recovery_info) {
     case modelmodify::kContinue:
-      return "kContinue";
+      return "Continue";
     case modelmodify::kFail:
-      return "kFail";
+      return "Fail";
     case modelmodify::kNotSet:
-      return "kNotSet";
+      return "NotSet";
     case modelmodify::kRestartOm:
-      return "kRestartOm";
+      return "RestartOm";
     default:
       return "Unknown recovery info";
   }
@@ -329,10 +329,10 @@ inline static const char* RecoveryTxt(int recovery_info) {
 //    // Do some other error handling...
 //  }
 //
-class ObjectModification {
+class ModelModification {
  public:
-  ObjectModification();
-  ~ObjectModification(); // TODO(Lennart) Finalize the Object Manager
+  ModelModification();
+  ~ModelModification(); // TODO(Lennart) Finalize the Object Manager
 
   // Set CCB Flags
   // If flag SA_IMM_CCB_REGISTERED_OI is set then an Object Implementer must
@@ -343,7 +343,7 @@ class ObjectModification {
 
   // Returns False if an unrecoverable problem occurs. This may for example be
   // a validation error
-  bool DoModification(CcbDescriptor modifications);
+  bool DoModelModification(CcbDescriptor modifications);
 
   // Get more information if DoModification return Fail
   ErrorInfo GetErrorInfo(void) { return error_info_; }
@@ -356,7 +356,6 @@ class ObjectModification {
   int CreateCcb(void);
 
   int AdminOwnerSet(std::vector<std::string>& objects, SaImmScopeT scope);
-  //int AdminOwnerRelease(void);
 
   // Handle om_ccb_object_create()
   int AddCreates(std::vector<CreateDescriptor>& create_descriptors);
@@ -364,6 +363,9 @@ class ObjectModification {
   // Handle om_ccb_object_delete()
   int AddDeletes(std::vector<DeleteDescriptor>& delete_descriptors);
   int AddDelete(DeleteDescriptor& delete_descriptor);
+  // Handle om_ccb_object_modify()
+  int AddModifies(std::vector<ModifyDescriptor>& modify_descriptors);
+  int AddModify(ModifyDescriptor& modify_descriptor);
 
   int ApplyModifications(void);
 
@@ -394,7 +396,7 @@ class ObjectModification {
   uint64_t modification_timeout_;
   SaImmCcbFlagsT ccb_flags_;
 
-  DELETE_COPY_AND_MOVE_OPERATORS(ObjectModification);
+  DELETE_COPY_AND_MOVE_OPERATORS(ModelModification);
 };
 
 } // namespace modelmodify
diff --git a/src/smf/smfd/imm_modify_demo/ccbdemo_create.cc 
b/src/smf/smfd/imm_modify_demo/ccbdemo_create.cc
index 124abe9eb..f09125db3 100644
--- a/src/smf/smfd/imm_modify_demo/ccbdemo_create.cc
+++ b/src/smf/smfd/imm_modify_demo/ccbdemo_create.cc
@@ -426,9 +426,9 @@ int main(void) {
   //PrintCcbDescriptor(test_ccb);
   cout << endl;
 
-  modelmodify::ObjectModification model_modifier;
+  modelmodify::ModelModification model_modifier;
   model_modifier.SetCcbFlags(0);
-  if (model_modifier.DoModification(test_ccb) == false) {
+  if (model_modifier.DoModelModification(test_ccb) == false) {
     cout << "DoModification() Fail" << endl;
   }
 
diff --git a/src/smf/smfd/imm_modify_demo/ccbdemo_delete.cc 
b/src/smf/smfd/imm_modify_demo/ccbdemo_delete.cc
index 534433194..f81456179 100644
--- a/src/smf/smfd/imm_modify_demo/ccbdemo_delete.cc
+++ b/src/smf/smfd/imm_modify_demo/ccbdemo_delete.cc
@@ -159,9 +159,9 @@ int main() {
   delete_object.object_name = "TestObj2=1";
   test_ccb.AddDelete(delete_object);
 
-  modelmodify::ObjectModification model_modifier;
+  modelmodify::ModelModification model_modifier;
   model_modifier.SetCcbFlags(0); // No OI for this class/objects of this class
-  if (model_modifier.DoModification(test_ccb) == false) {
+  if (model_modifier.DoModelModification(test_ccb) == false) {
     cout << "DoModification() Fail" << endl;
   }
 
diff --git a/src/smf/smfd/imm_modify_demo/ccbdemo_modify.cc 
b/src/smf/smfd/imm_modify_demo/ccbdemo_modify.cc
index 399267052..d64e31e45 100644
--- a/src/smf/smfd/imm_modify_demo/ccbdemo_modify.cc
+++ b/src/smf/smfd/imm_modify_demo/ccbdemo_modify.cc
@@ -126,7 +126,7 @@ int main() {
   cout << "Become AO of the object to be modified" << endl;
   immom::ImmOmAdminOwnerSet ao_setter(ao_handle.GetHandle());
   ao_setter.AddObjectName("TestObj1=1,safApp=safSmfService"); // Object
-  if (ao_setter.SetAdminOwner(SA_IMM_SUBTREE) == false) {
+  if (ao_setter.SetAdminOwner(SA_IMM_ONE) == false) {
     cout << "AO Set Fail, " << ao_setter.ais_error_string() << endl;
     return -1;
   }
@@ -135,27 +135,27 @@ int main() {
 
 
   cout << "Add modify operation(s) to CCB" << endl;
-//  immom::ImmOmCcbObjectDelete deleter(ccb_handle.GetHandle());
-//  if (deleter.AddObjectDeleteToCcb("TestObj1=1,safApp=safSmfService")
-//                                   == false) {
-//    cout << "AddObjectDeleteToCcb() Fail, " << deleter.ais_error_string()
-//         << endl;
-//  }
   std::string object1 = "TestObj1=1,safApp=safSmfService";
   //std::string object2 = "TestObj2=1";
 
   immom::ImmOmCcbObjectModify modifier(ccb_handle.GetHandle(), object1);
 
   // Add 10 and 20 to existing SaUint32TValues
-//    AddAttributeValue(const std::string& name,
-//                    const std::vector<T*>& list_of_ptr_to_values);
   std::vector<SaUint32T> uint32_values{10, 20};
   std::vector<SaUint32T*> uint32_values_pointers;
   SaUint32T* val_p = uint32_values.data();
   uint32_values_pointers.push_back(val_p++);
   uint32_values_pointers.push_back(val_p);
 
+  // Replace the SaUint32TValue with 90
+  std::vector<SaUint32T> uint32_values1{90};
+  std::vector<SaUint32T*> uint32_values_pointers1;
+  val_p = uint32_values1.data();
+  uint32_values_pointers1.push_back(val_p);
+
+
   modifier.AddAttributeValue("SaUint32TValues", uint32_values_pointers);
+  modifier.ReplaceAttributeValue("SaUint32TValue", uint32_values_pointers1);
   if (modifier.AddObjectModifyToCcb() == false) {
     cout << "AddObjectModifyToCcb() Fail, " << modifier.ais_error_string()
          << endl;
@@ -167,14 +167,6 @@ int main() {
     return -1;
   }
 
-#if 0 // Don't do this
-  cout << "Release AO using ao_setter release method" << endl;
-  if (ao_setter.ReleaseAdminOwner() == false) {
-    cout << "AO release Fail, " << ao_setter.ais_error_string() << endl;
-    //return -1;
-  }
-#endif
-
   cout << "Clean up; Finalize OM handle" << endl;
   om_handle.FinalizeHandle();
 
@@ -183,8 +175,99 @@ int main() {
 #endif
 
 #if 1 // Modifying object using modelmodify
+void PrintValues(modelmodify::ModifyDescriptor modifier) {
+  cout << "Printing a modifier:" << endl;
+
+  cout << "modifier.object_name = " << modifier.object_name << endl;
+
+  cout << "Modifications:" << endl;
+  for (auto& modification : modifier.modifications) {
+    cout << "modification.modification_type = " <<
+        modification.modification_type << endl;
+    cout << "modification.attribute_descriptor.attribute_name = " <<
+        modification.attribute_descriptor.attribute_name << endl;
+    cout << "modification.attribute_descriptor.value_type = " <<
+        modification.attribute_descriptor.value_type << endl;
+    cout << "Values:" << endl;
+    for (auto& str_value :
+         modification.attribute_descriptor.values_as_strings) {
+      cout << "str_value = " << str_value << endl;
+    }
+  }
+  cout << endl;
+}
+
 int main() {
-  cout << "ccb_modify" << endl;
+  cout << "Modifying an object using 'modelmodify'. Object must exist" <<
+      endl;
+  cout << "Class: ImmTestValuesConfig" << endl;
+  cout << "Modify: TestObj1=1,safApp=safSmfService" << endl << endl;
+
+#if 1// Enable trace
+  unsigned int category_mask = 0xffffffff;
+  const char* logPath = PKGLOGDIR "/osafccbdemo1";
+  if (logtrace_init("ccbdemo1", logPath, category_mask) == -1) {
+    syslog(LOG_ERR, "osafntfimcnd logtrace_init FAILED");
+    /* We allow to execute anyway. */
+    cout << "logtrace_init() Fail" << endl;
+  } else {
+    //cout << "logtrace enabled" << endl;
+  }
+#endif
+
+  // Prepare extended name
+  setenv("SA_ENABLE_EXTENDED_NAMES", "1", 1);
+  osaf_extended_name_init();
+
+  // 
===========================================================================
+  // Add 10 and 20 to existing 'SaUint32TValues' attribute
+  // 
===========================================================================
+
+  // 1. Attribute descriptor
+  modelmodify::AttributeDescriptor uint32_multivalue_attribute;
+  uint32_multivalue_attribute.attribute_name = "SaUint32TValues";
+  uint32_multivalue_attribute.value_type = SA_IMM_ATTR_SAUINT32T;
+  uint32_multivalue_attribute.AddValue(std::to_string(10));
+  uint32_multivalue_attribute.AddValue(std::to_string(20));
+
+  // 1. Attribute modify descriptor
+  modelmodify::AttributeModifyDescriptor uint32_multivalue_modify;
+  uint32_multivalue_modify.modification_type = SA_IMM_ATTR_VALUES_ADD;
+  uint32_multivalue_modify.attribute_descriptor = uint32_multivalue_attribute;
+
+  // 2. Attribute descriptor
+  modelmodify::AttributeDescriptor uint32_attribute;
+  uint32_attribute.attribute_name = "SaUint32TValue";
+  uint32_attribute.value_type = SA_IMM_ATTR_SAUINT32T;
+  uint32_attribute.AddValue(to_string(90));
+
+  // 2. Attribute modify descriptor
+  modelmodify::AttributeModifyDescriptor uint32_modify;
+  uint32_modify.modification_type = SA_IMM_ATTR_VALUES_REPLACE;
+  uint32_modify.attribute_descriptor = uint32_attribute;
+
+  // Add modification to the attribute modification to the modify descriptor
+  modelmodify::ModifyDescriptor modification;
+  modification.object_name = "TestObj1=1,safApp=safSmfService";
+  modification.AddAttributeModification(uint32_multivalue_modify);
+  modification.AddAttributeModification(uint32_modify);
+
+  // LLDTEST Print modifier content
+  PrintValues(modification);
+
+  // Add the modify descriptor to the ccb descriptor
+  modelmodify::CcbDescriptor model_configuration_change;
+  model_configuration_change.AddModify(modification);
+
+  // Create a modifier object and do the modification described in the
+  // ccb descriptor 'model_configuration_change'
+  modelmodify::ModelModification model_changer;
+  model_changer.SetCcbFlags(0);
+  if (model_changer.DoModelModification(model_configuration_change) == false) {
+    cout << "DoModelModification() Fail" << endl;
+  } else {
+    cout << "DoModelModification() Success" << endl;
+  }
 
   return 0;
 }
diff --git a/src/smf/smfd/imm_om_api/common/imm_attribute.h 
b/src/smf/smfd/imm_om_api/common/imm_attribute.h
index a3412c876..d8c9b9bbb 100644
--- a/src/smf/smfd/imm_om_api/common/imm_attribute.h
+++ b/src/smf/smfd/imm_om_api/common/imm_attribute.h
@@ -18,9 +18,6 @@
 #ifndef SRC_LOG_IMMWRP_COMMON_IMM_ATTRIBUTE_H_
 #define SRC_LOG_IMMWRP_COMMON_IMM_ATTRIBUTE_H_
 
-#if 1 // LLDTEST
-#include <iostream>
-#endif
 #include <string.h>
 #include <string>
 #include <vector>
diff --git a/src/smf/smfd/imm_om_api/om_ccb_object_create.h 
b/src/smf/smfd/imm_om_api/om_ccb_object_create.h
index f16f1b000..656b9bfcb 100644
--- a/src/smf/smfd/imm_om_api/om_ccb_object_create.h
+++ b/src/smf/smfd/imm_om_api/om_ccb_object_create.h
@@ -119,9 +119,6 @@ class ImmOmCcbObjectCreate : public ImmBase {
  private:
   void FreeAllocatedMemory();
 
-  // TODO(Lennart) LLDTEST Remove
-  void traceAttrVal(SaImmAttrValuesT_2 **attribute_values);
-
  //private:
   std::string class_name_;
   std::string parent_object_;
-- 
2.15.1


------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Opensaf-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to