Do refactoring to get rid of using data converters in SMF.
The work includes 02 parts:

1) Part #1 (This patch): apply the approach to into the demo application
- testing CCB handling (test_ccbhdl.cc).

2) Part #2: apply the approach into SMF code.
---
 src/smf/Makefile.am                           |  11 +-
 .../smfd/imm_modify_config/imm_ccb_handle.cc  | 242 +++++++++
 .../smfd/imm_modify_config/imm_ccb_handle.h   | 491 ++++++++++++++++++
 src/smf/smfd/imm_modify_demo/test_ccbhdl.cc   | 464 ++++-------------
 src/smf/smfd/imm_om_ccapi/common/common.h     |   7 +-
 .../smfd/imm_om_ccapi/common/imm_attribute.cc |  35 +-
 .../smfd/imm_om_ccapi/common/imm_attribute.h  | 176 +++----
 .../smfd/imm_om_ccapi/common/imm_cpp_type.h   | 380 ++++++++++++++
 8 files changed, 1340 insertions(+), 466 deletions(-)
 create mode 100644 src/smf/smfd/imm_modify_config/imm_ccb_handle.cc
 create mode 100644 src/smf/smfd/imm_modify_config/imm_ccb_handle.h
 create mode 100644 src/smf/smfd/imm_om_ccapi/common/imm_cpp_type.h

diff --git a/src/smf/Makefile.am b/src/smf/Makefile.am
index 5eed2e683..372597866 100644
--- a/src/smf/Makefile.am
+++ b/src/smf/Makefile.am
@@ -119,11 +119,14 @@ noinst_HEADERS += \
 noinst_HEADERS += \
        src/smf/smfd/imm_modify_config/attribute.h \
        src/smf/smfd/imm_modify_config/add_operation_to_ccb.h \
-       src/smf/smfd/imm_modify_config/immccb.h
+       src/smf/smfd/imm_modify_config/immccb.h \
+       src/smf/smfd/imm_modify_config/imm_ccb_handle.h
+
 
 # IMM OM C++ APIs
 noinst_HEADERS += \
        src/smf/smfd/imm_om_ccapi/common/common.h \
+       src/smf/smfd/imm_om_ccapi/common/imm_cpp_type.h \
        src/smf/smfd/imm_om_ccapi/common/imm_attribute.h \
        src/smf/smfd/imm_om_ccapi/om_admin_owner_clear.h \
        src/smf/smfd/imm_om_ccapi/om_admin_owner_handle.h \
@@ -211,7 +214,9 @@ bin_osafsmfd_SOURCES = \
 bin_osafsmfd_SOURCES += \
        src/smf/smfd/imm_modify_config/attribute.cc \
        src/smf/smfd/imm_modify_config/add_operation_to_ccb.cc \
-       src/smf/smfd/imm_modify_config/immccb.cc
+       src/smf/smfd/imm_modify_config/immccb.cc \
+       src/smf/smfd/imm_modify_config/imm_ccb_handle.cc
+
 
 # IMM OM C++ APIs
 bin_osafsmfd_SOURCES += \
@@ -400,7 +405,7 @@ bin_test_ccbhdl_SOURCES = \
 bin_test_ccbhdl_SOURCES += \
        src/smf/smfd/imm_modify_config/attribute.cc \
        src/smf/smfd/imm_modify_config/add_operation_to_ccb.cc \
-       src/smf/smfd/imm_modify_config/immccb.cc
+       src/smf/smfd/imm_modify_config/imm_ccb_handle.cc
 
 # IMM OM C++ APIs
 bin_test_ccbhdl_SOURCES += \
diff --git a/src/smf/smfd/imm_modify_config/imm_ccb_handle.cc 
b/src/smf/smfd/imm_modify_config/imm_ccb_handle.cc
new file mode 100644
index 000000000..6dcc5cc70
--- /dev/null
+++ b/src/smf/smfd/imm_modify_config/imm_ccb_handle.cc
@@ -0,0 +1,242 @@
+/*      -*- OpenSAF  -*-
+ *
+ * (C) Copyright 2008 The OpenSAF Foundation
+ * Copyright Ericsson AB 2018 - All Rights Reserved.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
+ * under the GNU Lesser General Public License Version 2.1, February 1999.
+ * The complete license can be accessed from the following location:
+ * http://opensource.org/licenses/lgpl-license.php
+ * See the Copying file included with the OpenSAF distribution for full
+ * licensing terms.
+ *
+ * Author(s): Ericsson AB
+ *
+ */
+
+#include "smf/smfd/imm_modify_config/imm_ccb_handle.h"
+#include "smf/smfd/imm_om_ccapi/common/common.h"
+
+namespace modelmodify {
+
+static bool IsResorceAbort(SaImmCcbHandleT ccb_handle) {
+  TRACE_ENTER();
+  bool rc = false;
+  const SaStringT *err_out = nullptr;
+  SaAisErrorT ais = saImmOmCcbGetErrorStrings(ccb_handle, &err_out);
+  if ((ais == SA_AIS_OK) && (err_out != nullptr)) {
+    LOG_NO("%s: Error string: '%s'", __func__, err_out[0]);
+    std::string err_str(err_out[0]);
+    if (err_str.find("IMM: Resource abort: ") != std::string::npos) {
+      rc = true;
+    }
+  }
+  return rc;
+}
+
+// Judge the state based on the input @ais code only.
+static EJobState job_state(SaAisErrorT ais) {
+  if (ais == SA_AIS_OK) return EJobState::kOk;
+  bool bad_hdl = (ais == SA_AIS_ERR_BAD_HANDLE);
+  return bad_hdl ? EJobState::kRestart : EJobState::kFail;
+}
+
+// Judge the state based on both the input @ais and if the
+// CCB is aborted with error message "resource is aborted".
+static EJobState job_state(SaImmCcbHandleT h, SaAisErrorT ais) {
+  EJobState state = job_state(ais);
+  if (ais == SA_AIS_ERR_FAILED_OPERATION) {
+    state = (IsResorceAbort(h) ? EJobState::kRestart : EJobState::kFail);
+  }
+  return state;
+}
+
+// Judge the state based on three inputs: @ais code, and if that code
+// is tolerated or not, the last one is if the CCB is aborted with error
+// message "resource is aborted"
+static EJobState job_state(JobBase* job, SaImmCcbHandleT h, SaAisErrorT ais) {
+  EJobState state = job_state(h, ais);
+  assert(job && "invalid pointer");
+  if (job->is_ais_code_ignored(ais)) state = EJobState::kOk;
+  return state;
+}
+
+static EJobState job_state(JobBase* job, SaAisErrorT ais) {
+  EJobState state = job_state(ais);
+  assert(job && "invalid pointer");
+  if (job->is_ais_code_ignored(ais)) state = EJobState::kOk;
+  return state;
+}
+
+//==============================================================================
+// CcbCreateJob/CcbModifyJob/CcbDeleteJob class
+//==============================================================================
+ErrInfo CcbCreateJob::DoJob() {
+  ccb_create_obj_.AddObjectCreateToCcb();
+  SaAisErrorT ais = ccb_create_obj_.ais_error();
+  return {job_state(this, ccb_handle_, ais), ais, __PRETTY_FUNCTION__};
+}
+
+ErrInfo CcbModifyJob::DoJob() {
+  ccb_modify_obj_.AddObjectModifyToCcb();
+  SaAisErrorT ais = ccb_modify_obj_.ais_error();
+  return {job_state(this, ccb_handle_, ais), ais, __PRETTY_FUNCTION__};
+}
+
+ErrInfo CcbDeleteJob::DoJob() {
+  ccb_delete_obj_.AddObjectDeleteToCcb(obj_name_);
+  SaAisErrorT ais = ccb_delete_obj_.ais_error();
+  return {job_state(this, ccb_handle_, ais), ais, __PRETTY_FUNCTION__};
+}
+
+//==============================================================================
+// JobExecutor class
+//==============================================================================
+ErrInfo JobExecutor::InitializeOmHandle() {
+  TRACE_ENTER();
+  ImmBase::RetryControl RetryTiming;
+  RetryTiming.interval = base::kFourtyMilliseconds;
+  RetryTiming.timeout = 60000;
+  handle_obj_.ChangeDefaultRetryControl(RetryTiming);
+  bool ret = handle_obj_.InitializeHandle();
+  EJobState state = ret ? EJobState::kOk : EJobState::kFail;
+  return {state, handle_obj_.ais_error(), __PRETTY_FUNCTION__};
+}
+
+ErrInfo JobExecutor::InitializeAdminOwnerHandle() {
+  TRACE_ENTER();
+  SaImmHandleT om_handle = handle_obj_.GetHandle();
+  ao_handle_obj_.ReleaseOwnershipOnFinalize();
+  ao_handle_obj_.InitializeHandle(om_handle);
+  SaAisErrorT ais = ao_handle_obj_.ais_error();
+  return {job_state(ais), ais, __PRETTY_FUNCTION__};
+}
+
+ErrInfo JobExecutor::SetAdminOwner() {
+  TRACE_ENTER();
+  SaImmAdminOwnerHandleT ao_handle = ao_handle_obj_.GetHandle();
+  SaImmScopeT scope = SA_IMM_ONE;
+  SaAisErrorT ais = SA_AIS_OK;
+
+  ao_set_obj_.UpdateHandle(ao_handle);
+  for (const auto& job : job_list_) {
+    std::string obj = job->object();
+    TRACE("object = %s", obj.c_str());
+    if (obj == "") continue;
+    if (job->job_type() == EJobType::kCcbDelete) {
+      scope = SA_IMM_SUBTREE;
+    }
+    ao_set_obj_.ClearObjectNames();
+    ao_set_obj_.AddObjectName(obj);
+    base::Timer timer(kExistTimeout);
+    bool ret = false;
+    while (timer.is_timeout() == false && ret == false) {
+      ret = ao_set_obj_.SetAdminOwner(scope);
+      ais = ao_set_obj_.ais_error();
+      if (ais == SA_AIS_ERR_EXIST) {
+        base::Sleep(base::MillisToTimespec(kExistWait));
+        continue;
+      }
+      break;
+    }
+    if (ret == false && job_state(job, ais) != EJobState::kOk)
+      return {job_state(ais), ais, __PRETTY_FUNCTION__};
+  }
+  return {EJobState::kOk, ais, __PRETTY_FUNCTION__};
+}
+
+ErrInfo JobExecutor::InitializeCcbHandle() {
+  TRACE_ENTER();
+  SaImmAdminOwnerHandleT ao_handle = ao_handle_obj_.GetHandle();
+  ccb_handle_obj_.InitializeHandle(ao_handle);
+  SaAisErrorT ais = ccb_handle_obj_.ais_error();
+  return {job_state(ais), ais, __PRETTY_FUNCTION__};
+}
+
+ErrInfo JobExecutor::DoJobs() {
+  TRACE_ENTER();
+  ErrInfo info = {EJobState::kOk, SA_AIS_OK, __PRETTY_FUNCTION__};
+  for (auto& job : job_list_) {
+    job->UpdateHandle(ccb_handle_obj_.GetHandle());
+    info = job->Execute();
+    if (info.result != EJobState::kOk) {
+      return info;
+    }
+  }
+  return info;
+}
+
+ErrInfo JobExecutor::ApplyCcb() {
+  TRACE_ENTER();
+  ccb_handle_obj_.ApplyCcb();
+  SaAisErrorT ais = ccb_handle_obj_.ais_error();
+  SaImmCcbHandleT ccb_handle = ccb_handle_obj_.GetHandle();
+  return {job_state(ccb_handle, ais), ais, __PRETTY_FUNCTION__};
+
+}
+
+ErrInfo JobExecutor::FinalizeHandles() {
+  ErrInfo info = {EJobState::kOk, SA_AIS_OK, __PRETTY_FUNCTION__};
+  ccb_handle_obj_.FinalizeHandle();
+  ao_handle_obj_.FinalizeHandle();
+  handle_obj_.FinalizeHandle();
+  return info;
+}
+
+bool JobExecutor::Execute() {
+  TRACE_ENTER();
+  uint64_t timeout = 120000;
+  base::Timer timer{timeout};
+  bool ret = false;
+  ErrInfo info;
+  // Keep below elements in the right order is important.
+  using PreExeMethods = ErrInfo (JobExecutor::*)();
+  PreExeMethods methods[] = {
+    // Pre-processings (setup handles)
+    &JobExecutor::InitializeOmHandle,
+    &JobExecutor::InitializeAdminOwnerHandle,
+    &JobExecutor::InitializeCcbHandle,
+    &JobExecutor::SetAdminOwner,
+    // Do jobs
+    &JobExecutor::DoJobs,
+    // Post-processing (commit)
+    &JobExecutor::ApplyCcb
+  };
+
+  while (timer.is_timeout() == false) {
+    FinalizeHandles();
+
+    bool restart = false, stop = false;
+    for (auto& f : methods) {
+      info = (this->*f)();
+      if (info.result == EJobState::kFail) {
+        LOG_NO("Failed at the function: %s, reason: %s",
+               info.at.c_str(), saf_error(info.ais));
+        stop = true;
+        break;
+      } else if (info.result == EJobState::kRestart) {
+        TRACE("Restart the CCB. Fail at %s, reason: %s",
+              info.at.c_str(), saf_error(info.ais));
+        restart = true;
+        break;
+      }
+    }
+
+    if (stop) break;
+    if (restart) continue;
+
+    ret = true;
+    break;
+  }
+
+  // All handles are just released when JobExecutor object is destroyed
+  // or run out of its scope. This make JobExecutor reusable
+
+  // FinalizeHandles();
+  error_info_ = info;
+  return ret;
+}
+
+}  // namespace modelmodify
diff --git a/src/smf/smfd/imm_modify_config/imm_ccb_handle.h 
b/src/smf/smfd/imm_modify_config/imm_ccb_handle.h
new file mode 100644
index 000000000..1f7e793a7
--- /dev/null
+++ b/src/smf/smfd/imm_modify_config/imm_ccb_handle.h
@@ -0,0 +1,491 @@
+/*      -*- OpenSAF  -*-
+ *
+ * (C) Copyright 2008 The OpenSAF Foundation
+ * Copyright Ericsson AB 2018 - All Rights Reserved.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
+ * under the GNU Lesser General Public License Version 2.1, February 1999.
+ * The complete license can be accessed from the following location:
+ * http://opensource.org/licenses/lgpl-license.php
+ * See the Copying file included with the OpenSAF distribution for full
+ * licensing terms.
+ *
+ * Author(s): Ericsson AB
+ *
+ */
+
+#ifndef SMF_SMFD_IMM_MODIFY_CONFIG_IMM_CCB_HANDLE_H_
+#define SMF_SMFD_IMM_MODIFY_CONFIG_IMM_CCB_HANDLE_H_
+
+#include <string>
+#include <vector>
+#include <set>
+
+#include "ais/include/saImm.h"
+#include "ais/include/saAis.h"
+
+#include "smf/smfd/imm_om_ccapi/om_handle.h"
+#include "smf/smfd/imm_om_ccapi/om_admin_owner_handle.h"
+#include "smf/smfd/imm_om_ccapi/om_ccb_handle.h"
+#include "smf/smfd/imm_om_ccapi/om_ccb_object_create.h"
+#include "smf/smfd/imm_om_ccapi/om_ccb_object_modify.h"
+#include "smf/smfd/imm_om_ccapi/om_ccb_object_delete.h"
+#include "smf/smfd/imm_om_ccapi/om_admin_owner_set.h"
+
+// Last input of JobExecutor constructor
+enum EJobMode {
+  // CCB is only allowed if IMM obj(s) has OI(s) attached to.
+  kOiRequired = 0,
+  // Allow CCB to proceed despite missing OIs
+  kNoOiRequired,
+  // Allow if there is no OI attached
+  kOiRequiredIfAny
+};
+
+// First input of CcbModifyJob::SetAttributeValue()
+enum EModifyType {
+  // Same as SA_IMM_ATTR_VALUES_ADD
+  kReplace = 0,
+  // Same as SA_IMM_ATTR_VALUES_DELETE
+  kDelete,
+  // Same as SA_IMM_ATTR_VALUES_ADD
+  kAdd
+};
+
+namespace modelmodify {
+
+const uint64_t kExistTimeout = 30000;  // 30 sec
+const uint64_t kExistWait    = 2000;   // 2 sec
+
+enum EJobState {
+  // No error happens or err is tolerated. It is ok to continue.
+  kOk,
+  // CCB is aborted and able to restart.
+  kRestart,
+  // CCB is aborted and unable to restart.
+  kFail
+};
+
+struct ErrInfo {
+  EJobState result;
+  SaAisErrorT ais;
+  std::string at;
+};
+
+// Job types: CCB create, CCB modify, or CCB delete
+enum EJobType {
+  kCcbCreate = 0,
+  kCcbModify,
+  kCcbDelete,
+  kUnknown
+};
+
+//==============================================================================
+// JobBase class
+//==============================================================================
+class JobBase {
+ public:
+  virtual ~JobBase() {}
+
+  ErrInfo Execute() { return DoJob(); }
+
+  // To give list of ais codes to be ignored (considered as SA_AIS_OK)
+  void ignore_ais_code(const std::vector<SaAisErrorT>& ignore_list) {
+    ignore_list_ = ignore_list;
+  }
+
+  void ignore_ais_code(SaAisErrorT ignore_ais) {
+    ignore_list_.push_back(ignore_ais);
+  }
+
+  bool is_ais_code_ignored(SaAisErrorT ais) {
+    for (auto code : ignore_list_) {
+      if (code == ais) return true;
+    }
+    return false;
+  }
+
+  virtual void UpdateHandle(const SaImmCcbHandleT& ccb_handle) = 0;
+  virtual const std::string& object() const = 0;
+  virtual EJobType job_type() const = 0;
+
+ protected:
+  JobBase() : ignore_list_{} {}
+
+ private:
+  virtual ErrInfo DoJob() = 0;
+  std::vector<SaAisErrorT> ignore_list_;
+};
+
+//==============================================================================
+// CcbCreateJob class represents IMM object creation job.
+//
+// Example of seting up the job:
+// CcbCreateJob create_job{"TestClass"};
+// create_job.SetParentName("a=b");
+// create_job.SetAttributeValue("dn", &dn_obj);
+// create_job.SetAttributeValue("uint32_attr", &uint32_value);
+// create_job.SetAttributeValue<SaUint64T>("multi_uint64", {1, 2, 3});
+//==============================================================================
+class CcbCreateJob : public JobBase {
+ public:
+  explicit CcbCreateJob(const std::string& class_name)
+      : parent_dn_{}
+      , ccb_create_obj_{0} {
+    ccb_create_obj_.SetClassName(class_name);
+  }
+
+  ~CcbCreateJob() {}
+
+  void UpdateHandle(const SaImmCcbHandleT& ccb_handle) {
+    ccb_handle_ = ccb_handle;
+    ccb_create_obj_.UpdateHandle(ccb_handle);
+  }
+
+  CcbCreateJob& SetParentName(const std::string& parent) {
+    ccb_create_obj_.SetParentName(parent);
+    parent_dn_ = parent;
+    return *this;
+  }
+
+  // Two way of giving attribute value to an attribute name:
+  // 1) Pass pointer to lvalue(s).
+  // E.g: std::string value{"hello"};
+  // SetAttributeValue("Attr1", &value);
+
+  // 2) Pass rvalue(s)
+  // E.g: SetAttributeValue<SaUint32T>("uint32tattr", 10);
+  template <typename T>
+  CcbCreateJob& SetAttributeValue(const std::string& name,
+                                  T* ptr_to_value = nullptr);
+  template <typename T>
+  CcbCreateJob& SetAttributeValue(const std::string& name,
+                                  const std::vector<T*>& ptr_to_values);
+  template <typename T>
+  CcbCreateJob& SetAttributeValue(const std::string& name, T value);
+
+  template <typename T>
+  CcbCreateJob& SetAttributeValue(const std::string& name,
+                                  const std::vector<T>& values);
+
+  const std::string& object() const { return parent_dn_; }
+  EJobType job_type() const { return EJobType::kCcbCreate; }
+
+ private:
+  ErrInfo DoJob();
+
+  std::string parent_dn_;
+  SaImmCcbHandleT ccb_handle_;
+  immom::ImmOmCcbObjectCreate ccb_create_obj_;
+};
+
+//==============================================================================
+// CcbModifyJob class represents IMM object modification job.
+//
+// Example of seting up the job:
+// CcbModifyJob modify_job{"obj=dn"};
+// modify_job.SetAttributeValue(EModifytype::kAdd, "uint32_attr", 
&uint32_attr);
+// modify_job.SetAttributeValue(EModifytype::kDelete, "str_attr", &str_value);
+//==============================================================================
+class CcbModifyJob : public JobBase {
+ public:
+  explicit CcbModifyJob(const std::string& obj_name)
+      : obj_name_{obj_name}
+      , ccb_handle_{0}
+      , ccb_modify_obj_{0, obj_name} {}
+  ~CcbModifyJob() {}
+
+  void UpdateHandle(const SaImmCcbHandleT& ccb_handle) {
+    ccb_handle_ = ccb_handle;
+    ccb_modify_obj_.UpdateHandle(ccb_handle);
+  }
+
+  template <typename T>
+  CcbModifyJob& SetAttributeValue(EModifyType modify_type,
+                                  const std::string& name,
+                                  T* ptr_to_value);
+  template <typename T>
+  CcbModifyJob& SetAttributeValue(EModifyType modify_type,
+                                  const std::string& name,
+                                  const std::vector<T*>& ptr_to_values);
+
+  template <typename T>
+  CcbModifyJob& SetAttributeValue(EModifyType modify_type,
+                                  const std::string& name,
+                                  T value);
+  template <typename T>
+  CcbModifyJob& SetAttributeValue(EModifyType modify_type,
+                                  const std::string& name,
+                                  const std::vector<T>& values);
+  const std::string& object() const { return obj_name_; }
+  EJobType job_type() const { return EJobType::kCcbModify; }
+
+ private:
+  ErrInfo DoJob();
+
+  std::string obj_name_;
+  SaImmCcbHandleT ccb_handle_;
+  immom::ImmOmCcbObjectModify ccb_modify_obj_;
+};
+
+//==============================================================================
+// CcbDeleteJob class represents IMM object deletion job.
+//
+// Example of seting up the job:
+// CcbDeleteJob delete_job{"obj=dn"};
+//==============================================================================
+class CcbDeleteJob : public JobBase {
+ public:
+  explicit CcbDeleteJob(const std::string& obj_name)
+      : obj_name_{obj_name}
+      , ccb_handle_{0}
+      , ccb_delete_obj_{0} {}
+  ~CcbDeleteJob() {}
+
+  void UpdateHandle(const SaImmCcbHandleT& ccb_handle) {
+    ccb_handle_ = ccb_handle;
+    ccb_delete_obj_.UpdateHandle(ccb_handle);
+  }
+
+  const std::string& object() const { return obj_name_; }
+  EJobType job_type() const { return EJobType::kCcbDelete; }
+
+ private:
+  ErrInfo DoJob();
+
+  std::string obj_name_;
+  SaImmCcbHandleT ccb_handle_;
+  immom::ImmOmCcbObjectDelete ccb_delete_obj_;
+};
+
+//==============================================================================
+// JobExecutor is used to execute all added-in jobs.
+//
+// Usage:
+// JobExecutor jobex{"AdminOwnerName", EJobMode::kNoOiRequired}
+// jobex.AddJob(&create_job);
+// jobex.AddJob(&delete_Job);
+// jobex.AddJob(&modify_job);
+// if (jobex.Execute() == true) {
+//   CCB is committed
+// } else {
+//   CCB is aborted.
+// }
+//
+// jobex.ClearJobs().AddJobs({&job1, &job2, job3});
+// jobex.Execute();
+//==============================================================================
+class JobExecutor {
+ public:
+  // @name: admin owner name for all added-in jobs
+  // @mode: refer to @JobMode
+  explicit JobExecutor(const std::string& name, EJobMode mode)
+      : ccb_flags_{to_ccb_flag(mode)}
+      , handle_obj_{}
+      , ao_handle_obj_{0, name}
+      , ao_set_obj_{0}
+      , ccb_handle_obj_{0, ccb_flags_}
+      , job_list_{} {}
+
+  ~JobExecutor() { FinalizeHandles(); }
+
+  // Add job (create/modify/delete) one by one or list of jobs.
+  JobExecutor& AddJob(JobBase* job) {
+    job_list_.push_back(job);
+    return *this;
+  }
+
+  JobExecutor& AddJobs(const std::vector<JobBase*>& job_list) {
+    job_list_ = job_list;
+    return *this;
+  }
+
+  ErrInfo error_info() { return error_info_; }
+
+  JobExecutor& ClearJobs() {
+    job_list_.clear();
+    return *this;
+  }
+
+  // Execute all added-in jobs. Return true if all jobs are committed,
+  // false otherwise. Call error_info() to get error information.
+  bool Execute();
+
+ private:
+  ErrInfo InitializeOmHandle();
+  ErrInfo InitializeCcbHandle();
+  ErrInfo InitializeAdminOwnerHandle();
+  ErrInfo SetAdminOwner();
+  ErrInfo DoJobs();
+  ErrInfo ApplyCcb();
+  ErrInfo FinalizeHandles();
+  SaImmCcbFlagsT to_ccb_flag(EJobMode mode) {
+    if (mode == EJobMode::kOiRequired) {
+      return SA_IMM_CCB_REGISTERED_OI;
+    } else if (mode == EJobMode::kNoOiRequired) {
+      return 0;
+    } else {
+      return SA_IMM_CCB_REGISTERED_OI | SA_IMM_CCB_ALLOW_NULL_OI;
+    }
+  }
+  SaImmCcbFlagsT ccb_flags_;
+  immom::ImmOmHandle handle_obj_;
+  immom::ImmOmAdminOwnerHandle ao_handle_obj_;
+  immom::ImmOmAdminOwnerSet ao_set_obj_;
+  immom::ImmOmCcbHandle ccb_handle_obj_;
+  ErrInfo error_info_;
+  std::vector<JobBase*> job_list_;
+};
+
+template <typename T>
+CcbCreateJob& CcbCreateJob::SetAttributeValue(const std::string& name,
+                                              T* ptr_to_value) {
+  ccb_create_obj_.SetAttributeValue(name, ptr_to_value);
+  return *this;
+}
+
+template <typename T>
+CcbCreateJob& CcbCreateJob::SetAttributeValue(
+    const std::string& name,
+    const std::vector<T*>& ptr_to_values) {
+  ccb_create_obj_.SetAttributeValue(name, ptr_to_values);
+  return *this;
+}
+
+template <typename T>
+CcbCreateJob& CcbCreateJob::SetAttributeValue(const std::string& name,
+                                              T value) {
+  T tmp = value;
+  ccb_create_obj_.SetAttributeValue(name, &tmp);
+  return *this;
+}
+
+template <typename T>
+CcbCreateJob& CcbCreateJob::SetAttributeValue(const std::string& name,
+                                              const std::vector<T>& values) {
+  T tmp[values.size()];
+  std::vector<T*> ptr_to_values;
+
+  int i = 0;
+  for (const auto& v : values) {
+    tmp[i] = v;
+    ptr_to_values.push_back(&tmp[i]);
+    i++;
+  }
+
+  ccb_create_obj_.SetAttributeValue(name, ptr_to_values);
+  return *this;
+}
+
+template <typename T>
+CcbModifyJob& CcbModifyJob::SetAttributeValue(
+    EModifyType modify_type,
+    const std::string& name,
+    T* ptr_to_value) {
+  switch (modify_type) {
+    case EModifyType::kReplace:
+      ccb_modify_obj_.ReplaceAttributeValue(name, ptr_to_value);
+      break;
+
+    case EModifyType::kDelete:
+      ccb_modify_obj_.DeleteAttributeValue(name, ptr_to_value);
+      break;
+
+    case EModifyType::kAdd:
+      ccb_modify_obj_.AddAttributeValue(name, ptr_to_value);
+      break;
+
+    default:
+      assert(0 && "Unknown Modify type");
+  }
+  return *this;
+}
+
+template <typename T>
+CcbModifyJob& CcbModifyJob::SetAttributeValue(
+    EModifyType modify_type,
+    const std::string& name,
+    const std::vector<T*>& ptr_to_values) {
+  switch (modify_type) {
+    case EModifyType::kReplace:
+      ccb_modify_obj_.ReplaceAttributeValue(name, ptr_to_values);
+      break;
+
+    case EModifyType::kDelete:
+      ccb_modify_obj_.DeleteAttributeValue(name, ptr_to_values);
+      break;
+
+    case EModifyType::kAdd:
+      ccb_modify_obj_.AddAttributeValue(name, ptr_to_values);
+      break;
+
+    default:
+      assert(0 && "Unknown Modify type");
+  }
+  return *this;
+}
+
+template <typename T>
+CcbModifyJob& CcbModifyJob::SetAttributeValue(
+    EModifyType modify_type,
+    const std::string& name,
+    T value) {
+  T tmp = value;
+  switch (modify_type) {
+    case EModifyType::kReplace:
+      ccb_modify_obj_.ReplaceAttributeValue(name, &tmp);
+      break;
+
+    case EModifyType::kDelete:
+      ccb_modify_obj_.DeleteAttributeValue(name, &tmp);
+      break;
+
+    case EModifyType::kAdd:
+      ccb_modify_obj_.AddAttributeValue(name, &tmp);
+      break;
+
+    default:
+      assert(0 && "Unknown Modify type");
+  }
+  return *this;
+}
+
+template <typename T>
+CcbModifyJob& CcbModifyJob::SetAttributeValue(
+    EModifyType modify_type,
+    const std::string& name,
+    const std::vector<T>& values) {
+  T tmp[values.size()];
+  std::vector<T*> ptr_to_values;
+
+  int i = 0;
+  for (const auto& v : values) {
+    tmp[i] = v;
+    ptr_to_values.push_back(&tmp[i]);
+    i++;
+  }
+
+  switch (modify_type) {
+    case EModifyType::kReplace:
+      ccb_modify_obj_.ReplaceAttributeValue(name, ptr_to_values);
+      break;
+
+    case EModifyType::kDelete:
+      ccb_modify_obj_.DeleteAttributeValue(name, ptr_to_values);
+      break;
+
+    case EModifyType::kAdd:
+      ccb_modify_obj_.AddAttributeValue(name, ptr_to_values);
+      break;
+
+    default:
+      assert(0 && "Unknown Modify type");
+  }
+  return *this;
+}
+
+}  // namespace modelmodify
+
+#endif
diff --git a/src/smf/smfd/imm_modify_demo/test_ccbhdl.cc 
b/src/smf/smfd/imm_modify_demo/test_ccbhdl.cc
index 727953edd..f13f34738 100644
--- a/src/smf/smfd/imm_modify_demo/test_ccbhdl.cc
+++ b/src/smf/smfd/imm_modify_demo/test_ccbhdl.cc
@@ -23,7 +23,7 @@
 #include <memory>
 #include <utility>
 #include <iostream>
-
+#include <algorithm>
 #include "ais/include/saImm.h"
 #include "ais/include/saAis.h"
 #include "base/osaf_extended_name.h"
@@ -32,7 +32,7 @@
 
 #include "smf/smfd/imm_modify_demo/common.h"
 
-#include "smf/smfd/imm_modify_config/immccb.h"
+#include "smf/smfd/imm_modify_config/imm_ccb_handle.h"
 
 #include "smf/smfd/imm_om_ccapi/common/common.h"
 #include "smf/smfd/imm_om_ccapi/om_admin_owner_clear.h"
@@ -56,101 +56,40 @@ using namespace std;
 void CreateOneObject(void) {
   // Create an object description
   // ============================
-  modelmodify::AttributeDescriptor attribute;
-  modelmodify::CreateDescriptor imm_object;
+  modelmodify::CcbCreateJob imm_object {"ImmTestValuesConfig"};
   std::string object_name = "Test1=1";
+  SaNameT a_name, a_name2, a_name3;
+
+  imm_object.SetParentName("safApp=safSmfService");
+  imm_object.SetAttributeValue("immTestValuesCfg", &object_name);
+  imm_object.SetAttributeValue<SaUint32T>("SaUint32TValues", {1, 2});
+  imm_object.SetAttributeValue<SaInt32T>("SaInt32TValues", {3, 4});
 
-  // Define the object
-  // -----------------
-  imm_object.class_name = "ImmTestValuesConfig";
-  imm_object.parent_name = "safApp=safSmfService";
-  // Set IMM Object name
-  attribute.attribute_name = "immTestValuesCfg";
-  attribute.value_type = SA_IMM_ATTR_SASTRINGT;
-  attribute.AddValue(object_name);
-  imm_object.AddAttribute(attribute);
-
-  // Set some attributes
-  // -------------------
-
-  // SA_UINT32_T multi-value attribute
-  attribute.attribute_name = "SaUint32TValues";
-  attribute.value_type = SA_IMM_ATTR_SAUINT32T;
-  // We are reusing so remove "old" values and add new ones
-  attribute.values_as_strings.clear();
-  attribute.AddValue(std::to_string(1));
-  attribute.AddValue(std::to_string(2));
-  // Add the attribute to the object
-  imm_object.AddAttribute(attribute);
-
-  // SA_INT32_T multi-value attribute
-  attribute.attribute_name = "SaInt32TValues";
-  attribute.value_type = SA_IMM_ATTR_SAINT32T;
-  attribute.values_as_strings.clear();
-  attribute.AddValue(std::to_string(3));
-  attribute.AddValue(std::to_string(4));
-  // Add the attribute to the object
-  imm_object.AddAttribute(attribute);
-
-  // SA_NAME_T multi-value attribute
-  SaNameT a_name;
-  attribute.attribute_name = "SaNameTValues";
-  attribute.value_type = SA_IMM_ATTR_SANAMET;
-  attribute.values_as_strings.clear();
-  // Add two short names
   osaf_extended_name_lend("a_name1", &a_name);
-  attribute.AddValue(modelmodify::SaNametToString(&a_name));
-  osaf_extended_name_lend("a_name2", &a_name);
-  attribute.AddValue(modelmodify::SaNametToString(&a_name));
+  osaf_extended_name_lend("a_name2", &a_name2);
   // Add a long name and a third short name
   char long_name[300];
-  for (size_t i = 0; i < 299; i++) {
-    long_name[i] = 'a';
-  }
+  memset(long_name, 'a', 299);
   long_name[299] = '\0';
-  osaf_extended_name_lend(long_name, &a_name);
-  attribute.AddValue(modelmodify::SaNametToString(&a_name));
-  osaf_extended_name_lend("a_name3", &a_name);
-  attribute.AddValue(modelmodify::SaNametToString(&a_name));
-  imm_object.AddAttribute(attribute);
+  osaf_extended_name_lend(long_name, &a_name3);
+  std::vector<SaNameT*> names = {&a_name, &a_name2, &a_name3};
+  //imm_object.SetAttributeValue("SaNameTValues", {&a_name, &a_name2, 
&a_name3});
+  imm_object.SetAttributeValue("SaNameTValues", names);
 
   // SA_UINT32_T single-value attribute
-  attribute.attribute_name = "SaUint32TValue";
-  attribute.value_type = SA_IMM_ATTR_SAUINT32T;
-  attribute.values_as_strings.clear();
-  // Note: Single value attribute so only one value can be added
-  attribute.AddValue(std::to_string(10));
-  imm_object.AddAttribute(attribute);
-
-  // Create a CCB descriptor and add the description of the object to create
-  // =======================================================================
-  modelmodify::CcbDescriptor CcbDescriptor;
-
-  CcbDescriptor.AddCreate(imm_object);
-
-  // Create a modification handler and use it to create the object as defined
-  // above
-  // ========================================================================
-
-  modelmodify::ModelModification ModelModifier;
+  imm_object.SetAttributeValue<SaUint32T>("SaUint32TValue", 10);
 
-  // Set CCB flag to inform IMM that there is no Object Implementer
-  ModelModifier.SetCcbFlags(0);
+  modelmodify::JobExecutor jobs{"Testing", EJobMode::kNoOiRequired};
+  jobs.AddJob(&imm_object);
 
   // Create the IMM object
-  if (ModelModifier.DoModelModification(CcbDescriptor) == false) {
+  if (jobs.Execute() == false) {
     cout << "Creation of '" << object_name << "' FAIL" << endl;
   } else {
     cout << "Creation of '" << object_name << "' SUCCESS" << endl;
   }
 }
 
-// Remove all modifications from a CCB descriptor so it can be reused
-void CcbDescriptorCleaner(modelmodify::CcbDescriptor& ccb_descriptor) {
-  ccb_descriptor.create_descriptors.clear();
-  ccb_descriptor.delete_descriptors.clear();
-  ccb_descriptor.modify_descriptors.clear();
-}
 
 // Fill in a create descriptor.
 // The created object will be given the name in 'object_name'
@@ -159,43 +98,17 @@ void CcbDescriptorCleaner(modelmodify::CcbDescriptor& 
ccb_descriptor) {
 // SaInt32TValues: 1, 2, 3
 // SaUint64TValues: 100, 200
 // SaTimeTValues: 10000
-void SetupObjectCreate1(const std::string object_name,
-                        modelmodify::CreateDescriptor& create_desc) {
-  modelmodify::AttributeDescriptor attribute;
-  // Prepare the create descriptor
-  create_desc.class_name = "ImmTestValuesConfig";
-  create_desc.parent_name = "safApp=safSmfService";
-  create_desc.attributes.clear();
-
-  // Set object name
-  attribute.attribute_name = "immTestValuesCfg";
-  attribute.value_type = SA_IMM_ATTR_SASTRINGT;
-  attribute.AddValue(object_name);
-  create_desc.AddAttribute(attribute);
-
-  // Set SaInt32TValues
-  attribute.values_as_strings.clear();
-  attribute.attribute_name = "SaInt32TValues";
-  attribute.value_type = SA_IMM_ATTR_SAINT32T;
-  attribute.AddValue(std::to_string(1));
-  attribute.AddValue(std::to_string(2));
-  attribute.AddValue(std::to_string(3));
-  create_desc.AddAttribute(attribute);
-
-  // Set SaUint64TValues
-  attribute.values_as_strings.clear();
-  attribute.attribute_name = "SaUint64TValues";
-  attribute.value_type = SA_IMM_ATTR_SAUINT64T;
-  attribute.AddValue(std::to_string(100));
-  attribute.AddValue(std::to_string(200));
-  create_desc.AddAttribute(attribute);
-
-  // Set SaTimeTValues
-  attribute.values_as_strings.clear();
-  attribute.attribute_name = "SaTimeTValues";
-  attribute.value_type = SA_IMM_ATTR_SATIMET;
-  attribute.AddValue(std::to_string(10000));
-  create_desc.AddAttribute(attribute);
+
+void SetupObjectCreate1(const std::string& object_name,
+                        modelmodify::CcbCreateJob& create_job) {
+  std::string obj_name = object_name;
+  create_job.SetParentName("safApp=safSmfService");
+  create_job.SetAttributeValue("immTestValuesCfg", &obj_name);
+  create_job.SetAttributeValue<SaInt32T>("SaInt32TValues", {1, 2, 3});
+  create_job.SetAttributeValue<SaUint64T>("SaUint64TValues", {100, 200});
+  CppSaTimeT value = 10000;
+  std::vector<CppSaTimeT*> times{&value};
+  create_job.SetAttributeValue<CppSaTimeT>("SaTimeTValues", times);
 }
 
 void WaitForUserAction(const std::string& message) {
@@ -230,7 +143,7 @@ int main() {
   // Prepare/enable extended name
   // ----------------------------
   setenv("SA_ENABLE_EXTENDED_NAMES", "1", 1);
-  
+
   if (EnableImmLongDn() == false) return -1;
 
   // Note: Long DN must be configured in IMM configuration object before
@@ -250,31 +163,15 @@ int main() {
   // Wait for the user to verify in another node and press Enter in this node
   WaitForUserAction("Verify creation of Test1=1,safApp=safSmfService");
 
-  // Create a modifier to be used here in main() and set CCB flag to handle
-  // that there is no Object Implementer for objects handled here
-  // ----------------------------------------------------------------------
-  modelmodify::ModelModification modifier;
-  modifier.SetCcbFlags(0);
-  // A CCB descriptor for the modifier
-  modelmodify::CcbDescriptor ccb_descriptor;
-
-  // We also need some model modification descriptors
-  modelmodify::CreateDescriptor create_descriptor;
-  modelmodify::ModifyDescriptor modify_descriptor;
-  modelmodify::DeleteDescriptor delete_descriptor;
-  // an attribute modify descriptor
-  modelmodify::AttributeDescriptor attribute_descriptor;
-  // and an attribute modify descriptor
-  modelmodify::AttributeModifyDescriptor attribute_modify_descriptor;
-
-  // Create and apply a CCB that creates two more objects
-  // ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
-
-  SetupObjectCreate1("Test1=2", create_descriptor);
-  ccb_descriptor.AddCreate(create_descriptor);
-  SetupObjectCreate1("Test1=3", create_descriptor);
-  ccb_descriptor.AddCreate(create_descriptor);
-  if (modifier.DoModelModification(ccb_descriptor) == false) {
+  modelmodify::CcbCreateJob create_job2("ImmTestValuesConfig");
+  modelmodify::CcbCreateJob create_job3("ImmTestValuesConfig");
+  SetupObjectCreate1("Test1=2", create_job2);
+  SetupObjectCreate1("Test1=3", create_job3);
+
+  modelmodify::JobExecutor jobs("Testing2", EJobMode::kNoOiRequired);
+  jobs.AddJob(&create_job2).AddJob(&create_job3);
+
+  if (jobs.Execute() == false) {
     cout << "Create two more objects in the same CCB, FAIL" << endl;
   } else {
     cout << "Create two more objects in the same CCB, SUCCESS" << endl;
@@ -295,61 +192,31 @@ int main() {
   //  Replace SaInt32TValues 3 and 4 with 5, 6, 7
   // All is done in the same CCB
 
-  // We are reusing the CCB descriptor so:
-  // Clean the CCB descriptor from the previous object creation
-  CcbDescriptorCleaner(ccb_descriptor);
-
   // Add a new object to the CBB. The new object is created within a function
   // that uses an attribute descriptor that is local to this function. This 
will
   // test that data is correctly handed over to the create descriptor
-  SetupObjectCreate1("Test1=4", create_descriptor);
-  ccb_descriptor.AddCreate(create_descriptor);
+  modelmodify::CcbCreateJob create_job4("ImmTestValuesConfig");
+  SetupObjectCreate1("Test1=4", create_job4);
 
   // Add two objects deletions
-  delete_descriptor.object_name = "Test1=2,safApp=safSmfService";
-  ccb_descriptor.AddDelete(delete_descriptor);
-  delete_descriptor.object_name = "Test1=3,safApp=safSmfService";
-  ccb_descriptor.AddDelete(delete_descriptor);
+  modelmodify::CcbDeleteJob delete_job2("Test1=2,safApp=safSmfService");
+  modelmodify::CcbDeleteJob delete_job3("Test1=3,safApp=safSmfService");
 
   // Setup the modifications for the "test1=1" object:
-  modify_descriptor.object_name = "Test1=1,safApp=safSmfService";
-  // Add a value to SaUint32TValues
-  // Clean attribute descriptor from any possible previous usage
-  attribute_descriptor.values_as_strings.clear();
-  attribute_descriptor.attribute_name = "SaUint32TValues";
-  attribute_descriptor.value_type = SA_IMM_ATTR_SAUINT32T;
-  attribute_descriptor.AddValue(std::to_string(4));
-  attribute_modify_descriptor.modification_type = SA_IMM_ATTR_VALUES_ADD;
-  attribute_modify_descriptor.attribute_descriptor = attribute_descriptor;
-  modify_descriptor.AddAttributeModification(attribute_modify_descriptor);
-  // Delete a value from SaNameTValues
-  attribute_descriptor.values_as_strings.clear();
   SaNameT a_name;  // Use a real SaNameT
   osaf_extended_name_lend("a_name1", &a_name);
-  attribute_descriptor.attribute_name = "SaNameTValues";
-  attribute_descriptor.value_type = SA_IMM_ATTR_SANAMET;
-  attribute_descriptor.AddValue(modelmodify::SaNametToString(&a_name));
-  attribute_modify_descriptor.modification_type = SA_IMM_ATTR_VALUES_DELETE;
-  attribute_modify_descriptor.attribute_descriptor = attribute_descriptor;
-  modify_descriptor.AddAttributeModification(attribute_modify_descriptor);
-  // Replace the values in SaInt32TValues
-  attribute_descriptor.attribute_name = "SaInt32TValues";
-  attribute_descriptor.value_type = SA_IMM_ATTR_SAINT32T;
-  attribute_descriptor.values_as_strings.clear();
-  attribute_descriptor.AddValue(std::to_string(5));
-  attribute_descriptor.AddValue(std::to_string(6));
-  attribute_descriptor.AddValue(std::to_string(7));
-  attribute_modify_descriptor.modification_type = SA_IMM_ATTR_VALUES_REPLACE;
-  attribute_modify_descriptor.attribute_descriptor = attribute_descriptor;
-  modify_descriptor.AddAttributeModification(attribute_modify_descriptor);
-
-  // Add the modifications to the CCB
-  ccb_descriptor.AddModify(modify_descriptor);
+  modelmodify::CcbModifyJob modify_job1("Test1=1,safApp=safSmfService");
+
+  modify_job1.SetAttributeValue<SaUint32T>(EModifyType::kAdd, 
"SaUint32TValues", 4);
+  modify_job1.SetAttributeValue(EModifyType::kDelete, "SaNameTValues", 
&a_name);
+  modify_job1.SetAttributeValue<SaInt32T>(EModifyType::kReplace, 
"SaInt32TValues", {5, 6, 7});
+
+  jobs.ClearJobs().AddJobs({&create_job4, &delete_job2, &delete_job3, 
&modify_job1});
 
   cout << "Modify the model using a mixed CCB START" << endl;
 
   // The modifier object is used here for the second time
-  if (modifier.DoModelModification(ccb_descriptor) == false) {
+  if (jobs.Execute() == false) {
     cout << "Modify the model using a mixed CCB, FAIL" << endl;
   } else {
     cout << "Modify the model using a mixed CCB, SUCCESS" << endl;
@@ -371,14 +238,12 @@ int main() {
   cout << "Cleanup by deleting the remaining Test1=1 and Test1=4 objects"
        << endl;
 
-  CcbDescriptorCleaner(ccb_descriptor);
-  delete_descriptor.object_name = "Test1=1,safApp=safSmfService";
-  ccb_descriptor.AddDelete(delete_descriptor);
-  delete_descriptor.object_name = "Test1=4,safApp=safSmfService";
-  ccb_descriptor.AddDelete(delete_descriptor);
+  modelmodify::CcbDeleteJob delete_job1("Test1=1,safApp=safSmfService");
+  modelmodify::CcbDeleteJob delete_job4("Test1=4,safApp=safSmfService");
+  jobs.ClearJobs().AddJob(&delete_job1).AddJob(&delete_job4);
 
   // The modifier object is used here for the third time
-  if (modifier.DoModelModification(ccb_descriptor) == false) {
+  if (jobs.Execute() == false) {
     cout << "Delete Test1=1 and Test1=4, FAIL" << endl;
   } else {
     cout << "Delete Test1=1 and Test1=4, SUCCESS" << endl;
@@ -391,114 +256,47 @@ int main() {
   // value_type. Use SA_IMM_ATTR_SAUINT32T where  SA_IMM_ATTR_SASTRINGT is the
   // correct type. The modification shall fail but there should not cause any
   // crash e.g. segv
-  // Create an object description
-  // ============================
-  // Reuse the create descriptor
-  create_descriptor.attributes.clear();
-  std::string object_name = "Test12=1";
 
   // Define the object
   // -----------------
-  create_descriptor.class_name = "ImmTestValuesConfig";
-  create_descriptor.parent_name = "safApp=safSmfService";
-  // Set IMM Object name
-  attribute_descriptor.attribute_name = "immTestValuesCfg";
-  attribute_descriptor.value_type = SA_IMM_ATTR_SASTRINGT;
-  // We are reusing so remove "old" values and add new ones
-  attribute_descriptor.values_as_strings.clear();
-  attribute_descriptor.AddValue(object_name);
-  create_descriptor.AddAttribute(attribute_descriptor);
-
-  // Set some attribute_descriptors
-  // -------------------
-
-  // SA_UINT32_T multi-value attribute_descriptor
-  attribute_descriptor.attribute_name = "SaUint32TValues";
-  attribute_descriptor.value_type = SA_IMM_ATTR_SAUINT32T;
-  attribute_descriptor.values_as_strings.clear();
-  attribute_descriptor.AddValue(std::to_string(1));
-  attribute_descriptor.AddValue(std::to_string(2));
-  // Add the attribute_descriptor to the object
-  create_descriptor.AddAttribute(attribute_descriptor);
-
-  // SA_INT32_T multi-value attribute_descriptor
-  attribute_descriptor.attribute_name = "SaInt32TValues";
-  attribute_descriptor.value_type = SA_IMM_ATTR_SAINT32T;
-  attribute_descriptor.values_as_strings.clear();
-  attribute_descriptor.AddValue(std::to_string(3));
-  attribute_descriptor.AddValue(std::to_string(4));
-  // Add the attribute_descriptor to the object
-  create_descriptor.AddAttribute(attribute_descriptor);
-
-  // SA_NAME_T multi-value attribute_descriptor
-  SaNameT a_name1;
-  attribute_descriptor.attribute_name = "SaNameTValues";
-  attribute_descriptor.value_type = SA_IMM_ATTR_SANAMET;
-  attribute_descriptor.values_as_strings.clear();
-  // Add two short names
+  std::string object_name{"Test12=1"};
+  SaNameT a_name1, a_name2, a_name3;
+  std::string str1{"A_string_value=1"};
+  std::string str2{"A_string_value=2"};
+  std::string str3{"A_string_value=3"};
+  std::string str4{"A_string_value=4"};
+  std::vector<SaNameT*> list_namet{&a_name1, &a_name2, &a_name3};
+  std::vector<std::string*> list_str{&str1, &str2, &str3, &str4};
   osaf_extended_name_lend("a_name11", &a_name1);
-  attribute_descriptor.AddValue(modelmodify::SaNametToString(&a_name1));
-  osaf_extended_name_lend("a_name12", &a_name1);
-  attribute_descriptor.AddValue(modelmodify::SaNametToString(&a_name1));
+  osaf_extended_name_lend("a_name12", &a_name2);
+
   // Add a long name and a third short name
   char long_name[300];
-  for (size_t i = 0; i < 299; i++) {
-    long_name[i] = 'a';
-  }
+  memset(long_name, 'a', 299);
   long_name[299] = '\0';
-  osaf_extended_name_lend(long_name, &a_name1);
-  attribute_descriptor.AddValue(modelmodify::SaNametToString(&a_name1));
-  osaf_extended_name_lend("a_name13", &a_name1);
-  attribute_descriptor.AddValue(modelmodify::SaNametToString(&a_name1));
-  create_descriptor.AddAttribute(attribute_descriptor);
-
-  // SA_UINT32_T single-value attribute_descriptor
-  attribute_descriptor.attribute_name = "SaUint32TValue";
-  attribute_descriptor.value_type = SA_IMM_ATTR_SAUINT32T;
-  attribute_descriptor.values_as_strings.clear();
-  // Note: Single value attribute_descriptor so only one value can be added
-  attribute_descriptor.AddValue(std::to_string(10));
-  create_descriptor.AddAttribute(attribute_descriptor);
-
-
-  // SA_IMM_ATTR_SASTRINGT multi value attribute_descriptor
-  // SA_IMM_ATTR_SAUINT32T will be incorrectly used here
-  attribute_descriptor.attribute_name = "SaStringValues";
-  attribute_descriptor.value_type = SA_IMM_ATTR_SAUINT32T;
-  attribute_descriptor.values_as_strings.clear();
-  attribute_descriptor.AddValue("A_string_value=1");
-  attribute_descriptor.AddValue("A_string_value=2");
-  attribute_descriptor.AddValue("A_string_value=3");
-  attribute_descriptor.AddValue("A_string_value=4");
-  create_descriptor.AddAttribute(attribute_descriptor);
-
-  // Reuse the ccb_descriptor and add the object creation
-  CcbDescriptorCleaner(ccb_descriptor);
-  ccb_descriptor.AddCreate(create_descriptor);
-
-  // Do the modification
-  // Set CCB flag to inform IMM that there is no Object Implementer
-  modifier.SetCcbFlags(0);
-
+  osaf_extended_name_lend(long_name, &a_name3);
+
+  modelmodify::CcbCreateJob create_job12("ImmTestValuesConfig");
+  create_job12.SetParentName("safApp=safSmfService");
+  create_job12.SetAttributeValue("immTestValuesCfg", &object_name);
+  create_job12.SetAttributeValue<SaUint32T>("SaUint32TValues", {1, 2});
+  create_job12.SetAttributeValue<SaInt32T>("SaInt32TValues", {3, 4});
+  create_job12.SetAttributeValue("SaNameTValues", list_namet);
+  create_job12.SetAttributeValue("SaStringValues", list_str);
+  // Mistmatch b/w IMM model data type(SaUint32T) and value data type 
(SaInt32T)
+  create_job12.SetAttributeValue<SaInt32T>("SaUint32TValue", 10);
+
+  jobs.ClearJobs().AddJob(&create_job12);
   cout <<
   "In the request to create a Test12=1,safApp=safSmfService object " << endl <<
   "a string attribute is incorrectly given SA_IMM_ATTR_SAUINT32T as " << endl 
<<
   "IMM type. This shall fail in a controlled way" << endl;
 
   // Create the IMM object
-  if (modifier.DoModelModification(ccb_descriptor) == false) {
+  if (jobs.Execute() == false) {
     cout << "Creation of '" << object_name << "' FAIL" << endl;
     cout << "This fail is intentional so if we get here the test is SUCCESS"
          << endl << endl;
-
-    cout << "Error information:" << endl;
-    modelmodify::ErrorInformation error_info;
-    modifier.GetErrorInformation(error_info);
-    cout << "Failing API: '" << error_info.api_name << "' " << endl;
-    cout << "AIS error code: " << saf_error(error_info.ais_error) << endl;
-    cout << "This is an internal error so there shall be no valid AIS error "
-            "code or AIS API-name" << endl;
-    cout << "If 'Failng API:' is empty then test is SUCCESS" << endl;
   } else {
     cout << "Creation of '" << object_name << "' SUCCESS" << endl;
     cout << "Test case FAIL" << endl;
@@ -520,41 +318,25 @@ int main() {
   cout << "Then with ignore_ais_err_exist = true, shall succeed. However "
           "no new object is created" << endl << endl;
 
-
   // Reuse the create descriptor
-  create_descriptor.attributes.clear();
-  object_name = "Test12=2";
+  object_name = "Test13=2";
 
   // Define the object
   // Note: No values other than the object name is given
   // -----------------
-  create_descriptor.class_name = "ImmTestValuesConfig";
-  create_descriptor.parent_name = "safApp=safSmfService";
-  // Set IMM Object name
-  attribute_descriptor.attribute_name = "immTestValuesCfg";
-  attribute_descriptor.value_type = SA_IMM_ATTR_SASTRINGT;
-  // We are reusing so remove "old" values and add new ones
-  attribute_descriptor.values_as_strings.clear();
-  attribute_descriptor.AddValue(object_name);
-  create_descriptor.AddAttribute(attribute_descriptor);
-
-  // Reuse the ccb_descriptor and add the object creation
-  CcbDescriptorCleaner(ccb_descriptor);
-  ccb_descriptor.AddCreate(create_descriptor);
-
-  // Do the modification
-  // Set CCB flag to inform IMM that there is no Object Implementer
-  modifier.SetCcbFlags(0);
+  modelmodify::CcbCreateJob create_job13("ImmTestValuesConfig");
+  SetupObjectCreate1(object_name, create_job13);
+
+  jobs.ClearJobs().AddJob(&create_job13);
 
   cout << "1. First Create. Shall succeed" << endl;
-  if (modifier.DoModelModification(ccb_descriptor) == false) {
+  if (jobs.Execute() == false) {
     cout << "Creation of '" << object_name << "' FAIL" << endl;
 
     cout << "Error information:" << endl;
-    modelmodify::ErrorInformation error_info;
-    modifier.GetErrorInformation(error_info);
-    cout << "Failing API: '" << error_info.api_name << "' " << endl;
-    cout << "AIS error code: " << saf_error(error_info.ais_error) << endl;
+    modelmodify::ErrInfo info = jobs.error_info();
+    cout << "Failing at: '" << info.at << "' " << endl;
+    cout << "AIS error code: " << saf_error(info.ais) << endl;
     cout << endl;
 
     cout << "First object shall be created with no FAIL" << endl;
@@ -566,14 +348,15 @@ int main() {
 
   cout << "2. Second create of same object shall fail. "
           "Object already exist" << endl;
-  if (modifier.DoModelModification(ccb_descriptor) == false) {
+
+  jobs.ClearJobs().AddJob(&create_job13);
+  if (jobs.Execute() == false) {
     cout << "Creation of '" << object_name << "' FAIL" << endl;
 
     cout << "Error information:" << endl;
-    modelmodify::ErrorInformation error_info;
-    modifier.GetErrorInformation(error_info);
-    cout << "Failing API: '" << error_info.api_name << "' " << endl;
-    cout << "AIS error code: " << saf_error(error_info.ais_error) << endl;
+    modelmodify::ErrInfo info = jobs.error_info();
+    cout << "Failing at: '" << info.at << "' " << endl;
+    cout << "AIS error code: " << saf_error(info.ais) << endl;
 
     cout << "Second creation of same object shall FAIL. Test SUCCESS" << endl;
   } else {
@@ -582,22 +365,13 @@ int main() {
   cout << endl;
 
   cout << "3. Third create of same object shall succeed." << endl;
-  cout << "   Set ignore_ais_err_exist = true and try again." << endl;
+  cout << "   Set ignore_ais_err = SA_AIS_ERR_EXIST and try again." << endl;
   cout << "   This time the modification shall not fail" << endl;
-  create_descriptor.ignore_ais_err_exist = true;
-  ccb_descriptor.create_descriptors.clear();
-  ccb_descriptor.AddCreate(create_descriptor);
 
-  if (modifier.DoModelModification(ccb_descriptor) == false) {
+  create_job13.ignore_ais_code(SA_AIS_ERR_EXIST);
+  jobs.ClearJobs().AddJob(&create_job13);
+  if (jobs.Execute() == false) {
     cout << "Creation of '" << object_name << "' FAIL" << endl;
-
-    cout << "Error information:" << endl;
-    modelmodify::ErrorInformation error_info;
-    modifier.GetErrorInformation(error_info);
-    cout << "Failing API: '" << error_info.api_name << "' " << endl;
-    cout << "AIS error code: " << saf_error(error_info.ais_error) << endl;
-
-    cout << "Third creation of same object failed. Test FAIL" << endl;
   } else {
     cout << "Third creation of same object did not fail. Test SUCCESS" << endl;
   }
@@ -606,43 +380,29 @@ int main() {
   // Try deleting an object that does not exist;
   // ignore_ais_err_not_exist = true
   // Shall SUCCEED but no object is deleted
-  std::string object_name_not_exist = "Test12=100";
+  std::string object_name_not_exist = "Test12=100,safApp=safSmfService";
   cout << "Deleting object that does not exist. Flag ignore_ais_err_not_exist "
-      "= true (default)" << endl;
-  delete_descriptor.object_name = object_name_not_exist + "," +
-                                  create_descriptor.parent_name;
-  CcbDescriptorCleaner(ccb_descriptor);
-  ccb_descriptor.AddDelete(delete_descriptor);
-  if (modifier.DoModelModification(ccb_descriptor) == false) {
-    cout << "Deleting object '" << delete_descriptor.object_name << "' FAIL"
+      "= true" << endl;
+
+  modelmodify::CcbDeleteJob delete_job5{object_name_not_exist};
+  delete_job5.ignore_ais_code(SA_AIS_ERR_NOT_EXIST);
+  jobs.ClearJobs().AddJob(&delete_job5);
+  if (jobs.Execute() == false) {
+    cout << "Deleting object '" << object_name_not_exist << "' FAIL"
          << endl;
     cout << "Test FAIL" << endl;
   } else {
     cout << "Test SUCCESS" << endl;
   }
 
-  // Cleanup by deleting the test object
-  delete_descriptor.object_name = object_name + "," +
-                                  create_descriptor.parent_name;
-  delete_descriptor.ignore_ais_err_not_exist = true;
-  CcbDescriptorCleaner(ccb_descriptor);
-  ccb_descriptor.AddDelete(delete_descriptor);
-  if (modifier.DoModelModification(ccb_descriptor) == false) {
-    cout << "Deleting object '" << delete_descriptor.object_name << "' FAIL"
-         << endl;
-  }
-
   // Try deleting an object that does not exist;
   // ignore_ais_err_not_exist = false
   cout << "Deleting object that does not exist. Flag ignore_ais_err_not_exist "
       "= false" << endl;
-  delete_descriptor.object_name = object_name_not_exist + "," +
-                                  create_descriptor.parent_name;
-  delete_descriptor.ignore_ais_err_not_exist = false;
-  CcbDescriptorCleaner(ccb_descriptor);
-  ccb_descriptor.AddDelete(delete_descriptor);
-  if (modifier.DoModelModification(ccb_descriptor) == false) {
-    cout << "Deleting object '" << delete_descriptor.object_name << "' FAIL"
+  modelmodify::CcbDeleteJob delete_job6{object_name_not_exist};
+  jobs.ClearJobs().AddJob(&delete_job6);
+  if (jobs.Execute() == false) {
+    cout << "Deleting object '" << object_name_not_exist << "' FAIL"
          << endl;
     cout << "Test SUCCESS" << endl;
   } else {
diff --git a/src/smf/smfd/imm_om_ccapi/common/common.h 
b/src/smf/smfd/imm_om_ccapi/common/common.h
index b9c87cb06..6c095189e 100644
--- a/src/smf/smfd/imm_om_ccapi/common/common.h
+++ b/src/smf/smfd/imm_om_ccapi/common/common.h
@@ -23,6 +23,7 @@
 #include "ais/include/saAis.h"
 #include "base/time.h"
 #include "base/saf_error.h"
+#include "smf/smfd/imm_om_ccapi/common/imm_cpp_type.h"
 
 // When getting SA_AIS_ERR_TRY_AGAIN, the retry loop will be run.
 // and in default, the interval between retries is kDefaultIntervalMs(40ms)
@@ -51,7 +52,7 @@ const SaUint8T kDefaultImmMinorVersion = 11;
 struct CppSaTimeT {
   CppSaTimeT() { time = 0; }
   explicit CppSaTimeT(SaTimeT t) : time{t} {};
-  // explicit CppSaTimeT(int t) : time{t} {};
+  CppSaTimeT(int t) : time{t} {};
 
   CppSaTimeT& operator=(SaTimeT t) {
     time = t;
@@ -146,7 +147,8 @@ SaImmValueTypeT ImmBase::GetAttributeValueType() {
     return SA_IMM_ATTR_SAUINT32T;
   } else if (std::is_same<T, SaInt64T>::value) {
     return SA_IMM_ATTR_SAINT64T;
-  } else if (std::is_same<T, CppSaTimeT>::value) {
+  } else if ((std::is_same<T, CppSaTimeT>::value) ||
+             (std::is_same<T, cpptime_t>::value)) {
     return SA_IMM_ATTR_SATIMET;
   } else if (std::is_same<T, SaUint64T>::value) {
     return SA_IMM_ATTR_SAUINT64T;
@@ -183,6 +185,7 @@ SaImmValueTypeT ImmBase::GetAttributeValueType() {
       std::is_same<T, SaConstStringT>::value || \
       std::is_same<T, std::string>::value    || \
       std::is_same<T, SaTimeT>::value        || \
+      std::is_same<T, cpptime_t>::value      || \
       std::is_same<T, SaAnyT>::value,           \
       "typename T is not supported");
 
diff --git a/src/smf/smfd/imm_om_ccapi/common/imm_attribute.cc 
b/src/smf/smfd/imm_om_ccapi/common/imm_attribute.cc
index c53fadaee..b6c80c062 100644
--- a/src/smf/smfd/imm_om_ccapi/common/imm_attribute.cc
+++ b/src/smf/smfd/imm_om_ccapi/common/imm_attribute.cc
@@ -15,7 +15,7 @@
  *
  */
 
-#include "imm_attribute.h"
+#include "smf/smfd/imm_om_ccapi/common/imm_attribute.h"
 #include "base/logtrace.h"
 
 void AttributeProperty::FormAttrValuesT_2(
@@ -25,7 +25,7 @@ void AttributeProperty::FormAttrValuesT_2(
   output->attrName = const_cast<char*>(attribute_name_.c_str());
   output->attrValueType = attribute_type_;
   output->attrValuesNumber = num_of_values_;
-  output->attrValues = attribute_values_pointers_;
+  output->attrValues = attribute_values_;
 }
 
 void AttributeProperty::FormSearchOneAttrT_2(
@@ -34,8 +34,7 @@ void AttributeProperty::FormSearchOneAttrT_2(
   assert(output != nullptr);
   output->attrName = const_cast<char*>(attribute_name_.c_str());
   output->attrValueType = attribute_type_;
-  void* value = (attribute_values_pointers_ == nullptr) ? nullptr :
-    attribute_values_pointers_[0];
+  void* value = (attribute_values_ == nullptr) ? nullptr : 
attribute_values_[0];
   output->attrValue = value;
 }
 
@@ -45,8 +44,7 @@ void AttributeProperty::FormAdminOperationParamsT_2(
   assert(output != nullptr);
   output->paramName = const_cast<char*>(attribute_name_.c_str());
   output->paramType = attribute_type_;
-  void* value = (attribute_values_pointers_ == nullptr) ? nullptr :
-    attribute_values_pointers_[0];
+  void* value = (attribute_values_ == nullptr) ? nullptr : 
attribute_values_[0];
   output->paramBuffer = value;
 }
 
@@ -57,8 +55,7 @@ void AttributeDefinition::FormAttrDefinitionT_2(
   output->attrName = const_cast<char*>(attribute_name_.c_str());
   output->attrValueType = attribute_type_;
   output->attrFlags = attribute_flags_;
-  void* value = (attribute_values_pointers_ == nullptr) ? nullptr :
-    attribute_values_pointers_[0];
+  void* value = (attribute_values_ == nullptr) ? nullptr : 
attribute_values_[0];
   output->attrDefaultValue = value;
 }
 
@@ -72,44 +69,44 @@ void AttributeModification::FormAttrModificationT_2(
 
 void AttributeProperty::FreeMemory() {
   TRACE_ENTER();
-  if (attribute_values_pointers_ == nullptr) return;
+  if (attribute_values_ == nullptr) return;
   switch (attribute_type_) {
     case SA_IMM_ATTR_SAINT32T:
-      delete[] reinterpret_cast<SaInt32T**>(attribute_values_pointers_);
+      delete[] reinterpret_cast<SaInt32T**>(attribute_values_);
       break;
 
     case SA_IMM_ATTR_SAUINT32T:
-      delete[] reinterpret_cast<SaUint32T**>(attribute_values_pointers_);
+      delete[] reinterpret_cast<SaUint32T**>(attribute_values_);
       break;
 
     case SA_IMM_ATTR_SAINT64T:
-      delete[] reinterpret_cast<SaInt64T**>(attribute_values_pointers_);
+      delete[] reinterpret_cast<SaInt64T**>(attribute_values_);
       break;
 
     case SA_IMM_ATTR_SAUINT64T:
-      delete[] reinterpret_cast<SaUint64T**>(attribute_values_pointers_);
+      delete[] reinterpret_cast<SaUint64T**>(attribute_values_);
       break;
 
     case SA_IMM_ATTR_SANAMET:
-      delete[] reinterpret_cast<SaNameT**>(attribute_values_pointers_);
+      delete[] reinterpret_cast<SaNameT**>(attribute_values_);
       break;
 
     case SA_IMM_ATTR_SAFLOATT:
-      delete[] reinterpret_cast<SaFloatT**>(attribute_values_pointers_);
+      delete[] reinterpret_cast<SaFloatT**>(attribute_values_);
       break;
 
     case SA_IMM_ATTR_SADOUBLET:
-      delete[] reinterpret_cast<SaDoubleT**>(attribute_values_pointers_);
+      delete[] reinterpret_cast<SaDoubleT**>(attribute_values_);
       break;
 
     case SA_IMM_ATTR_SASTRINGT:
-      delete[] reinterpret_cast<SaStringT**>(attribute_values_pointers_);
+      delete[] reinterpret_cast<SaStringT**>(attribute_values_);
       break;
 
     default:
-      delete[] reinterpret_cast<SaAnyT**>(attribute_values_pointers_);
+      delete[] reinterpret_cast<SaAnyT**>(attribute_values_);
       break;
   }
 
-  attribute_values_pointers_ = nullptr;
+  attribute_values_ = nullptr;
 }
diff --git a/src/smf/smfd/imm_om_ccapi/common/imm_attribute.h 
b/src/smf/smfd/imm_om_ccapi/common/imm_attribute.h
index d4794eb84..e349289e5 100644
--- a/src/smf/smfd/imm_om_ccapi/common/imm_attribute.h
+++ b/src/smf/smfd/imm_om_ccapi/common/imm_attribute.h
@@ -1,6 +1,6 @@
 /*      -*- OpenSAF  -*-
  *
- * Copyright Ericsson AB 2018 - All Rights Reserved.
+ * Copyright Ericsson AB 2017 - All Rights Reserved.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
@@ -18,11 +18,12 @@
 #ifndef SMF_SMFD_IMM_OM_CCAPI_COMMON_IMM_ATTRIBUTE_H_
 #define SMF_SMFD_IMM_OM_CCAPI_COMMON_IMM_ATTRIBUTE_H_
 
-#include <string.h>
+#include <cstring>
 #include <string>
 #include <vector>
 #include "ais/include/saImm.h"
 #include "smf/smfd/imm_om_ccapi/common/common.h"
+#include "smf/smfd/imm_om_ccapi/common/imm_cpp_type.h"
 
 //>
 // These below 03 classes represent C IMM data structures
@@ -58,70 +59,75 @@
 //
 // Example:
 // AttributeProperty* attribute = new AttributeProperty(name);
-// attribute->set_value<SaUint32T>(value);
+// attribute->set_value<uint32_t>(value);
 //
 // SaImmAttrValuesT_2 immattr;
 // attribute->FormAttrValuesT_2(&immattr);
 //<
+
+
 class AttributeProperty {
  public:
   explicit AttributeProperty(const std::string& name)
       : attribute_name_{name},
-        attribute_values_pointers_{nullptr},
-        num_of_values_{0},
-        list_ptr_to_cpp_strings_{nullptr} {}
+        attribute_values_{nullptr},
+        num_of_values_{0}  {}
 
   virtual ~AttributeProperty() {
-    for (auto& item : list_ptr_to_cpp_strings_) {
-      if (item != nullptr)  delete[] item;
+    for (auto& item : values_) {
+      delete item;
     }
     FreeMemory();
   }
 
   template <typename T>
-  AttributeProperty& set_value(T* ptr_to_value) {
+  AttributeProperty& set_value(T* value) {
     attribute_type_ = ImmBase::GetAttributeValueType<T>();
-    if (ptr_to_value != nullptr) {
-      attribute_values_pointers_ = reinterpret_cast<void**>(new T*[1]());
-      assert(attribute_values_pointers_ != nullptr);
-      attribute_values_pointers_[0] = ptr_to_value;
+    if (value != nullptr) {
+      attribute_values_ = reinterpret_cast<void**>(new T*[1]());
+      assert(attribute_values_ != nullptr);
+      values_.push_back(GenerateCppType<T>(value));
+      attribute_values_[0] = values_[0]->data();
       num_of_values_ = 1;
     }
     return *this;
   }
 
   template <typename T>
-  AttributeProperty& set_value(const std::vector<T*>& list_of_ptr_to_values) {
+  AttributeProperty& set_value(const std::vector<T*>& values) {
     attribute_type_ = ImmBase::GetAttributeValueType<T>();
-    if (list_of_ptr_to_values.empty() == false) {
-      size_t size = list_of_ptr_to_values.size();
-      attribute_values_pointers_ = reinterpret_cast<void**>(new T*[size]());
-      assert(attribute_values_pointers_ != nullptr);
+    if (values.empty() == false) {
+      size_t size = values.size();
+      attribute_values_ = reinterpret_cast<void**>(new T*[size]());
+      assert(attribute_values_ != nullptr);
       unsigned i = 0;
-      for (auto& ptr_to_value : list_of_ptr_to_values) {
-        attribute_values_pointers_[i++] = ptr_to_value;
+      for (auto& value : values) {
+        values_.push_back(GenerateCppType<T>(value));
+        attribute_values_[i] = values_[i]->data();
+        i++;
       }
       num_of_values_ = size;
     }
     return *this;
   }
 
-  // Convert this class object to given `output` C IMM data structure
+  const std::string& name() { return attribute_name_; }
+
+  // // Convert this class object to given `output` C IMM data structure
   void FormAttrValuesT_2(SaImmAttrValuesT_2* output) const;
   void FormSearchOneAttrT_2(SaImmSearchOneAttrT_2* output) const;
   void FormAdminOperationParamsT_2(SaImmAdminOperationParamsT_2* output) const;
 
  private:
   void FreeMemory();
+  template <typename T> base_t* GenerateCppType(T* value);
 
  protected:
   std::string attribute_name_;
-  void** attribute_values_pointers_;
-  SaUint32T num_of_values_;
+  void** attribute_values_;
+  uint32_t num_of_values_;
   SaImmValueTypeT attribute_type_;
-  // Introduce this attribute to deal with typename T = std::string.
-  // Each element holds C string which is returned by std::string.c_str();
-  std::vector<char*> list_ptr_to_cpp_strings_;
+  std::vector<base_t*> values_;
 };
 
 class AttributeDefinition : public AttributeProperty {
@@ -154,76 +160,66 @@ class AttributeModification : public AttributeProperty {
   SaImmAttrModificationTypeT modification_type_;
 };
 
-template<> inline AttributeProperty&
-AttributeProperty::set_value<std::string>(std::string* ptr_to_value) {
-  attribute_type_ = ImmBase::GetAttributeValueType<std::string>();
-  if (ptr_to_value != nullptr) {
-    size_t size = ptr_to_value->length();
-    attribute_values_pointers_ = reinterpret_cast<void**>(new char**[1]());
-    assert(attribute_values_pointers_ != nullptr);
-    num_of_values_ = 1;
-
-    // Trick to deal with typename std::string
-    list_ptr_to_cpp_strings_.resize(1);
-    list_ptr_to_cpp_strings_[0] = new char[size + 1]();
-    assert(list_ptr_to_cpp_strings_[0] != nullptr);
-    memcpy(list_ptr_to_cpp_strings_[0], ptr_to_value->c_str(), size);
-    attribute_values_pointers_[0] = &list_ptr_to_cpp_strings_[0];
-  }
-  return *this;
+template <>
+inline base_t* AttributeProperty::GenerateCppType<SaInt32T>(SaInt32T* value) {
+  return new i32_t(*value);
 }
 
-template<> inline AttributeProperty&
-AttributeProperty::set_value<std::string>(
-    const std::vector<std::string*>& list_of_ptr_to_values) {
-  attribute_type_ = ImmBase::GetAttributeValueType<std::string>();
-  if (list_of_ptr_to_values.empty() == false) {
-    size_t size = list_of_ptr_to_values.size();
-    attribute_values_pointers_ = reinterpret_cast<void**>(new char**[size]());
-    assert(attribute_values_pointers_ != nullptr);
-    num_of_values_ = size;
-
-    list_ptr_to_cpp_strings_.resize(size);
-    unsigned i = 0;
-    for (auto& ptr_to_value : list_of_ptr_to_values) {
-      size_t ssize = ptr_to_value->length();
-      list_ptr_to_cpp_strings_[i] = new char[ssize + 1]();
-      assert(list_ptr_to_cpp_strings_[i] != nullptr);
-      memcpy(list_ptr_to_cpp_strings_[i], ptr_to_value->c_str(), ssize);
-      attribute_values_pointers_[i] = &list_ptr_to_cpp_strings_[i];
-      i++;
-    }
-  }
-  return *this;
+template <>
+inline base_t* AttributeProperty::GenerateCppType<uint32_t>(uint32_t* value) {
+  return new u32_t(*value);
 }
 
-template <> inline AttributeProperty&
-AttributeProperty::set_value<CppSaTimeT>(CppSaTimeT* ptr_to_value) {
-  attribute_type_ = ImmBase::GetAttributeValueType<CppSaTimeT>();
-  if (ptr_to_value != nullptr) {
-    attribute_values_pointers_ = reinterpret_cast<void**>(new SaTimeT*[1]());
-    assert(attribute_values_pointers_ != nullptr);
-    attribute_values_pointers_[0] = &(ptr_to_value->time);
-    num_of_values_ = 1;
-  }
-  return *this;
+template <>
+inline base_t* AttributeProperty::GenerateCppType<SaInt64T>(SaInt64T* value) {
+  return new i64_t(*value);
 }
 
-template <> inline AttributeProperty&
-AttributeProperty::set_value<CppSaTimeT>(
-    const std::vector<CppSaTimeT*>& list_of_ptr_to_values) {
-  attribute_type_ = ImmBase::GetAttributeValueType<CppSaTimeT>();
-  if (list_of_ptr_to_values.empty() == false) {
-    size_t size = list_of_ptr_to_values.size();
-    attribute_values_pointers_ = reinterpret_cast<void**>(new 
SaTimeT*[size]());
-    assert(attribute_values_pointers_ != nullptr);
-    unsigned i = 0;
-    for (auto& ptr_to_value : list_of_ptr_to_values) {
-      attribute_values_pointers_[i++] = &(ptr_to_value->time);
-    }
-    num_of_values_ = size;
-  }
-  return *this;
+template <>
+inline base_t* AttributeProperty::GenerateCppType<SaUint64T>(SaUint64T* value) 
{
+  return new u64_t(*value);
+}
+
+template <>
+inline base_t* AttributeProperty::GenerateCppType<CppSaTimeT>(CppSaTimeT* 
value) {
+  return new t64_t(cpptime_t(value->time));
+}
+
+template <>
+inline base_t* AttributeProperty::GenerateCppType<SaFloatT>(SaFloatT* value) {
+  return new f64_t(*value);
+}
+
+template <>
+inline base_t* AttributeProperty::GenerateCppType<SaDoubleT>(SaDoubleT* value) 
{
+  return new d64_t(*value);
+}
+
+template <>
+inline base_t* AttributeProperty::GenerateCppType<SaNameT>(SaNameT* value) {
+  return new name_t(*value);
+}
+
+template <>
+inline base_t* AttributeProperty::GenerateCppType<SaStringT>(SaStringT* value) 
{
+  return new string_t(*value);
+}
+
+template <>
+inline base_t* AttributeProperty::GenerateCppType<SaConstStringT>(
+    SaConstStringT* value) {
+  return new string_t(*value);
+}
+
+template <>
+inline base_t* AttributeProperty::GenerateCppType<std::string>(
+    std::string* value) {
+  return new string_t(*value);
+}
+
+template <>
+inline base_t* AttributeProperty::GenerateCppType<SaAnyT>(SaAnyT* value) {
+  return new any_t(*value);
 }
 
 // For internal use only
diff --git a/src/smf/smfd/imm_om_ccapi/common/imm_cpp_type.h 
b/src/smf/smfd/imm_om_ccapi/common/imm_cpp_type.h
new file mode 100644
index 000000000..664df018f
--- /dev/null
+++ b/src/smf/smfd/imm_om_ccapi/common/imm_cpp_type.h
@@ -0,0 +1,380 @@
+#ifndef SMF_SMFD_IMM_OM_CCAPI_COMMON_IMM_CPP_TYPE_
+#define SMF_SMFD_IMM_OM_CCAPI_COMMON_IMM_CPP_TYPE_
+
+#include <saAis.h>
+#include <cstring>
+#include <string>
+#include <iostream>
+#include <saImm.h>
+#include "base/osaf_extended_name.h"
+
+//>
+// These data wrappers are mainly used in common/imm_attribute.h,
+// so that all IMM data types can be able to be stored in one container.
+//<
+
+// enum class ECppType {
+//   kInt32T = 1,
+//   kUint32T,
+//   kInt64T,
+//   kUint64T,
+//   kTimeT,
+//   kNameT,
+//   kFloatT,
+//   kDoubleT,
+//   kStringT,
+//   kAnyT
+// };
+
+struct cpptime_t {
+  cpptime_t() {
+    data_ = 0;
+  }
+
+  explicit cpptime_t(SaTimeT i) {
+    data_ = i;
+  }
+
+  explicit cpptime_t(int i) {
+    data_ = static_cast<SaTimeT>(i);
+  }
+
+  explicit cpptime_t(int64_t i) {
+    data_ = static_cast<SaTimeT>(i);
+  }
+
+  cpptime_t& operator=(const SaTimeT& i) {
+    data_ = i;
+    return *this;
+  }
+
+  cpptime_t& operator=(const cpptime_t& i) {
+    data_ = i.data_;
+    return *this;
+  }
+
+  bool operator==(const cpptime_t& i) {
+    return data_ == i.data_;
+  }
+
+  bool operator==(SaTimeT& i) {
+    return data_ == i;
+  }
+
+  friend bool operator==(const SaTimeT& i, const cpptime_t& ii) {
+    return i == ii.data_;
+  }
+
+  friend bool operator==(SaTimeT& i, cpptime_t& ii) {
+    return i == ii.data_;
+  }
+
+  bool operator==(int i) {
+    return data_ == static_cast<SaTimeT>(i);
+  }
+
+  SaTimeT operator()() {
+    return data_;
+  }
+
+  SaTimeT* operator&() { return &data_; }
+
+ private:
+  SaTimeT data_;
+};
+
+class base_t {
+ public:
+  virtual void* data() = 0;
+  virtual ~base_t() {}
+  virtual void display() = 0;
+  // virtual SaImmValueTypeT type() = 0;
+};
+
+template<typename T>
+class numeric_t : public base_t {
+ public:
+  numeric_t() {
+    data_ = 0;
+  }
+
+  explicit numeric_t(T i) {
+    data_ = i;
+  }
+
+  explicit numeric_t(SaDoubleT i) {
+    data_ = static_cast<SaDoubleT>(i);
+  }
+
+  explicit numeric_t(int i) {
+    data_ = static_cast<T>(i);
+  }
+
+  explicit numeric_t(int64_t i) {
+    data_ = static_cast<T>(i);
+  }
+
+  numeric_t(numeric_t<T>& i) {
+    data_ = i.data_;
+  }
+
+  numeric_t(const numeric_t<T>& i) {
+    data_ = i.data_;
+  }
+
+  bool operator==(const T& i) const {
+    return data_ == i;
+  }
+
+  const T operator()() const {
+    return data_;
+  }
+
+  void* data() { return &data_; }
+
+  void display() {
+    std::cout << "\tdata: " << data_ << std::endl;
+  }
+
+ private:
+  T data_;
+};
+
+template<>
+class numeric_t<SaInt32T> : public base_t {
+ public:
+  numeric_t() {
+    data_ = 0;
+  }
+
+  explicit numeric_t(SaInt32T i) {
+    data_ = i;
+  }
+
+  numeric_t(numeric_t<SaInt32T>& i) {
+    data_ = i.data_;
+  }
+
+  numeric_t(const numeric_t<SaInt32T>& i) {
+    data_ = i.data_;
+  }
+
+  bool operator==(const SaInt32T& i) const {
+    return data_ == i;
+  }
+
+  const SaInt32T operator()() const {
+    return data_;
+  }
+
+  void* data() { return &data_; }
+
+  void display() {
+    std::cout << "\tdata: " << data_ << std::endl;
+  }
+
+ private:
+  SaInt32T data_;
+};
+
+template<>
+class numeric_t<SaDoubleT> : public base_t {
+ public:
+  numeric_t() {
+    data_ = 0;
+  }
+
+  explicit numeric_t(SaDoubleT i) {
+    data_ = i;
+  }
+
+  numeric_t(numeric_t<SaDoubleT>& i) {
+    data_ = i.data_;
+  }
+
+  numeric_t(const numeric_t<SaDoubleT>& i) {
+    data_ = i.data_;
+  }
+
+  bool operator==(const SaDoubleT& i) const {
+    return data_ == i;
+  }
+
+  const SaDoubleT operator()() const {
+    return data_;
+  }
+
+  void* data() { return &data_; }
+
+  void display() {
+    std::cout << "\tdata: " << data_ << std::endl;
+  }
+
+ private:
+  SaDoubleT data_;
+};
+
+class string_t : public base_t {
+public:
+  string_t() {
+    data_ = nullptr;
+  }
+
+  explicit string_t(const char* i) {
+    data_ = new char[strlen(i) + 1]();
+    memcpy(data_, i, strlen(i) + 1);
+  }
+
+  explicit string_t(const std::string& i) {
+    data_ = new char[i.length() + 1]();
+    memcpy(data_, i.c_str(), i.length());
+  }
+
+  string_t(const string_t& i) {
+    if (i.data_ == nullptr) return;
+    data_ = new char[strlen(i.data_) + 1]();
+    memcpy(data_, i(), strlen(i.data_) + 1);
+  }
+
+  string_t(string_t& i) {
+    if (i.data_ == nullptr) return;
+    data_ = new char[strlen(i.data_) + 1]();
+    memcpy(data_, i(), strlen(i.data_) + 1);
+  }
+
+  ~string_t() {
+    if (data_ != nullptr) {
+      delete[] data_;
+      data_ = nullptr;
+    }
+  }
+
+  const char* operator()() const {
+    return data_;
+  }
+
+  void* data() { return &data_; }
+
+  void display() {
+    std::cout << "\tdata: " << data_ << std::endl;
+  }
+
+private:
+  char* data_;
+};
+
+template<> inline void numeric_t<cpptime_t>::display() {
+  std::cout << "\tdata: " << data_() << std::endl;
+}
+
+class name_t : public base_t {
+ public:
+  name_t() {
+    buf_ = NULL;
+  }
+
+  name_t(name_t& i) {
+    buf_ = new char[strlen(i.buf_) + 1]();
+    memcpy(buf_, i.buf_, strlen(i.buf_) + 1);
+    osaf_extended_name_lend(buf_, &data_);
+  }
+
+  explicit name_t(SaNameT& i) {
+    SaConstStringT n = osaf_extended_name_borrow(&i);
+    buf_ = new char[strlen(n) + 1]();
+    memcpy(buf_, n, strlen(n) + 1);
+    osaf_extended_name_lend(buf_, &data_);
+  }
+
+   name_t(const name_t& i) {
+    buf_ = new char[strlen(i.buf_) + 1]();
+    memcpy(buf_, i.buf_, strlen(i.buf_) + 1);
+    osaf_extended_name_lend(buf_, &data_);
+  }
+
+  explicit name_t(std::string& i) {
+    buf_ = new char[i.length() + 1]();
+    memcpy(buf_, i.c_str(), i.length() + 1);
+    osaf_extended_name_lend(buf_, &data_);
+  }
+
+  explicit name_t(const std::string& i) {
+    buf_ = new char[i.length() + 1]();
+    memcpy(buf_, i.c_str(), i.length() + 1);
+    osaf_extended_name_lend(buf_, &data_);
+  }
+
+  ~name_t() {
+    if (buf_ != nullptr) {
+      delete[] buf_;
+      buf_ = nullptr;
+    }
+  }
+
+  const char* operator()() {
+    return buf_;
+  }
+
+  void* data() { return &data_; }
+
+  void display() {
+    std::cout << "\tdata: " << buf_ << std::endl;
+  }
+
+ private:
+  char* buf_;
+  SaNameT data_;
+};
+
+class any_t : public base_t {
+ public:
+  any_t() {
+    memset(&data_, 0, sizeof(SaAnyT));
+  }
+
+  ~any_t() {
+    if (data_.bufferAddr != nullptr) {
+      delete[] data_.bufferAddr;
+      data_.bufferAddr = nullptr;
+    }
+  }
+
+  explicit any_t(const SaAnyT& i) {
+    data_.bufferSize = i.bufferSize;
+    data_.bufferAddr = new SaUint8T[i.bufferSize]();
+    memcpy(reinterpret_cast<char*>(data_.bufferAddr),
+           i.bufferAddr, i.bufferSize);
+  }
+
+  explicit any_t(const char* i, size_t size) {
+    data_.bufferSize = size;
+    data_.bufferAddr = new SaUint8T[size]();
+    memcpy(reinterpret_cast<char*>(data_.bufferAddr), i, size);
+  }
+
+  explicit any_t(const char* i) : any_t{i, strlen(i)} { }
+  explicit any_t(const std::string& i) : any_t{i.c_str()} { }
+
+  const SaAnyT* operator()() {
+    return &data_;
+  }
+
+  void* data() { return &data_; }
+
+  void display() {
+    std::cout << "\tdata: " << data_.bufferAddr << std::endl;
+  }
+
+ private:
+  SaAnyT data_;
+};
+
+using i32_t = numeric_t<SaInt32T>;
+using u32_t = numeric_t<SaUint32T>;
+using i64_t = numeric_t<SaInt64T>;
+using u64_t = numeric_t<SaUint64T>;
+using f64_t = numeric_t<SaFloatT>;
+using d64_t = numeric_t<SaDoubleT>;
+using t64_t = numeric_t<cpptime_t>;
+
+#endif // SMF_SMFD_IMM_OM_CCAPI_COMMON_IMM_CPP_TYPE_
-- 
2.18.0


------------------------------------------------------------------------------
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
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to