Hi a Thanh,

Please ignore the duplicated attribute id in previous comment, multi values have the same attribute id.

Thanks

Minh

On 1/7/20 11:43 am, minhchau wrote:

Hi a Thanh,

Please see my very first comments inline with [M].

Another minor bug, I think it exists before this change, there are two Attribute ID within the same value as shown below.

numAttributes: 6
- Attribute ID: 0 -
 Attribute Type: (11) SA_NTF_VALUE_STRING
 Old Attribute Present: Yes
 Old Attribute:
 Attribute Value: "immcfg_SC-1_603"
 Attribute Value: "immcfg_SC-1_603"
- Attribute ID: 1 -
 Attribute Type: (11) SA_NTF_VALUE_STRING
 Old Attribute Present: Yes
 Old Attribute:
 Attribute Value: "OsafNtfCmTestCFG"
 Attribute Value: "OsafNtfCmTestCFG"
- Attribute ID: 2 -
 Attribute Type: (7) SA_NTF_VALUE_UINT64
 Old Attribute Present: Yes
 Old Attribute:
 Attribute Value: 3
 Attribute Value: 3
- Attribute ID: 3 -
 Attribute Type: (4) SA_NTF_VALUE_UINT32
 Old Attribute Present: Yes
 Old Attribute:
 Attribute Value: 1
 Attribute Value: 1
*- Attribute ID: 4 -*
 Attribute Type: (4) SA_NTF_VALUE_UINT32
 Old Attribute Present: Yes
 Old Attribute:
 Attribute Value: 32
 Attribute Value: 1
*- Attribute ID: 4 -*
 Attribute Type: (4) SA_NTF_VALUE_UINT32
 Old Attribute Present: No
 Attribute Value: 2

Thanks

Minh

On 30/6/20 9:32 pm, Thanh Nguyen wrote:
1) When IMM changes an attribute with NOTIFY flag, ntfimcn
currently sends the changed attribute values in notification data.
With the enhancement, ntfimcn fetches the old attribute values,
corresponding to the changed attribute values, if exist in IMM,
and include the old attribute values in notification data.
2) Test suite ntftest is updated.
---
  src/ntf/Makefile.am                 |   2 +
  src/ntf/apitest/test_ntf_imcn.cc    | 838 ++++++++++++++++++----------
  src/ntf/apitest/tet_ntf_common.cc   |  85 +++
  src/ntf/apitest/tet_ntf_common.h    |   2 +
  src/ntf/ntfimcnd/ntfimcn_common.c   | 398 +++++++++++++
  src/ntf/ntfimcnd/ntfimcn_common.h   | 123 ++++
  src/ntf/ntfimcnd/ntfimcn_imm.c      |  64 +++
  src/ntf/ntfimcnd/ntfimcn_main.h     |   2 +
  src/ntf/ntfimcnd/ntfimcn_notifier.c | 234 +++++++-
  9 files changed, 1457 insertions(+), 291 deletions(-)
  create mode 100755 src/ntf/ntfimcnd/ntfimcn_common.c
  create mode 100755 src/ntf/ntfimcnd/ntfimcn_common.h

diff --git a/src/ntf/Makefile.am b/src/ntf/Makefile.am
index a03eab10c..95210ae5d 100644
--- a/src/ntf/Makefile.am
+++ b/src/ntf/Makefile.am
@@ -108,6 +108,7 @@ noinst_HEADERS += \
        src/ntf/ntfimcnd/ntfimcn_imm.h \
        src/ntf/ntfimcnd/ntfimcn_main.h \
        src/ntf/ntfimcnd/ntfimcn_notifier.h \
+       src/ntf/ntfimcnd/ntfimcn_common.h \
        src/ntf/tools/ntfclient.h \
        src/ntf/tools/ntfconsumer.h
@@ -171,6 +172,7 @@ bin_osafntfimcnd_CPPFLAGS = \
  bin_osafntfimcnd_SOURCES = \
        src/ntf/ntfimcnd/ntfimcn_main.c \
        src/ntf/ntfimcnd/ntfimcn_notifier.c \
+       src/ntf/ntfimcnd/ntfimcn_common.c \
        src/ntf/ntfimcnd/ntfimcn_imm.c
bin_osafntfimcnd_LDADD = \
diff --git a/src/ntf/apitest/test_ntf_imcn.cc b/src/ntf/apitest/test_ntf_imcn.cc
index 6fc5fc831..284851e1d 100644
--- a/src/ntf/apitest/test_ntf_imcn.cc
+++ b/src/ntf/apitest/test_ntf_imcn.cc
@@ -55,6 +55,8 @@ static char BUF1_STR[sizeof(BUF1) + 1] = { '\0' };
  static char BUF2_STR[sizeof(BUF2) + 1] = { '\0' };
  static char BUF3_STR[sizeof(BUF3) + 1] = { '\0' };
+#define OLD_ATTR_PRESENT_DEFAULT SA_FALSE
+
  /**
   * Callback routine, called when subscribed notification arrives.
   */
@@ -168,6 +170,124 @@ static SaBoolT bufs_equal1(const SaUint8T *recbuf,
    return rc;
  }
+
+static void print_notification_attr(SaNtfNotificationHandleT nHandle,
+    SaNtfElementIdT attributeId,
+    SaNtfValueTypeT attributeType,
+    SaNtfValueT* value,
+    int idx) {
+  SaUint16T numElem = 0;
+  char *str = NULL;
+  SaAisErrorT rc = SA_AIS_OK;
+
+  switch (attributeType) {
+  case SA_NTF_VALUE_STRING: {
+    rc = saNtfPtrValGet(
+        nHandle,
+        value,
+        reinterpret_cast<void **>(&str), &numElem);
+    if (rc == SA_AIS_OK) {
+      printf("[%d]: Id:%d Type:%d Value:(%d)%s\n", idx,
+        attributeId, attributeType, numElem, str);
+    } else {
+      printf("[%d]: Id:%d Type:%d Value:(%d)%s\n", idx,
+        attributeId, attributeType, numElem, "<Empty>");
+    }
+    break;
+  }
+  case SA_NTF_VALUE_UINT32: {
+    printf("[%d]: Id:%d Type:%d Value:%u\n", idx,
+        attributeId, attributeType, value->uint32Val);
+    break;
+  }
+  case SA_NTF_VALUE_INT32: {
+    printf("[%d]: Id:%d Type:%d Value:%d\n", idx,
+        attributeId, attributeType, value->int32Val);
+    break;
+  }
+  case SA_NTF_VALUE_UINT64: {
+    printf("[%d]: Id:%d Type:%d Value:%llu\n", idx,
+        attributeId, attributeType, value->uint64Val);
+    break;
+  }
+  case SA_NTF_VALUE_INT64: {
+    printf("[%d]: Id:%d Type:%d Value:%lld\n", idx,
+        attributeId, attributeType, value->int64Val);
+    break;
+  }
+  case SA_NTF_VALUE_FLOAT: {
+    printf("[%d]: Id:%d Type:%d Value:%f\n", idx,
+        attributeId, attributeType, value->floatVal);
+    break;
+  }
+  case SA_NTF_VALUE_DOUBLE: {
+    printf("[%d]: Id:%d Type:%d Value:%f\n", idx,
+        attributeId, attributeType, value->doubleVal);
+    break;
+  }
+  case SA_NTF_VALUE_LDAP_NAME:
+  case SA_NTF_VALUE_BINARY: {
+    SaUint8T *binptr = NULL;
+    rc = saNtfPtrValGet(
+        nHandle,
+        value,
+        reinterpret_cast<void **>(&binptr), &numElem);
+    if (rc == SA_AIS_OK) {
+      printf("[%d]: Id:%d Type:%d NumBytes:%u\n", idx,
+             attributeId, attributeType,
+             numElem);
+      print_mem((const unsigned char*) binptr, numElem);
+    } else {
+      printf("[%d]: Id:%d Type:%d NumBytes:(%u)%s\n", idx,
+        attributeId, attributeType, numElem, "<Empty>");
+    }
+    break;
+  }
+  default:
+    printf("Unsupported attribute type: %d\n",
+        attributeType);
+    break;
+  }
+}
+
+static void print_old_attrs(SaNtfNotificationHandleT nHandle,
+    SaNtfAttributeChangeT* attrChange, SaUint16T numAttributes) {
+  // Skip of none of the attribute exist
+  int count = -1;
+  for (int i = 0; i < numAttributes; ++i) {
+    // There is at least one old attribute value
+    if (attrChange[i].oldAttributePresent == SA_TRUE) {
+      count = i;
+      break;
+    }
+  }
+  // Nothing found, skip
+  if (count == -1)
+    return;
+  printf("Num possible old attributes    : %d\n", numAttributes);
+  for (int i = 0; i < numAttributes; ++i) {
+    if (attrChange[i].oldAttributePresent == SA_FALSE) {
+      printf("[%d]: Old Attribute not present\n", i);
+      continue;
+    }
+    print_notification_attr(nHandle,
+        attrChange[i].attributeId,
+        attrChange[i].attributeType,
+        &attrChange[i].oldAttributeValue, i);
+  }
+}
+
+static void print_new_attrs(SaNtfNotificationHandleT nHandle,
+    SaNtfAttributeChangeT* attrChange, SaUint16T numAttributes) {
+  printf("Num changed attributes   : %d\n", numAttributes);
+  for (int i = 0; i < numAttributes; ++i) {
+    print_notification_attr(nHandle,
+        attrChange[i].attributeId,
+        attrChange[i].attributeType,
+        &attrChange[i].newAttributeValue, i);
+  }
+}
+
  /**
   * Display the content of a notification.
   */
@@ -245,99 +365,10 @@ static void print_notif(NotifData *n) {
             nHeader->additionalInfo[i].infoType, numElem, str);
    }
    if (n->evType == SA_NTF_ATTRIBUTE_CHANGED) {
-    printf("Num changed attributes   : %d\n",
-           n->a_c_notif_ptr->numAttributes);
-    for (i = 0; i < n->a_c_notif_ptr->numAttributes; i++) {
-      if (n->a_c_notif_ptr->changedAttributes[i]
-        .attributeType == SA_NTF_VALUE_STRING) {
-        safassert(saNtfPtrValGet(
-            n->nHandle,
-            &n->a_c_notif_ptr->changedAttributes[i].newAttributeValue,
-            reinterpret_cast<void **>(&str), &numElem), SA_AIS_OK);
-        printf("[%d]: Id:%d Type:%d Value:(%d)%s\n", i,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .attributeId,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .attributeType,
-               numElem, str);
-      } else if (n->a_c_notif_ptr->changedAttributes[i]
-               .attributeType == SA_NTF_VALUE_UINT32) {
-        printf("[%d]: Id:%d Type:%d Value:%u\n", i,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .attributeId,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .attributeType,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .newAttributeValue.uint32Val);
-      } else if (n->a_c_notif_ptr->changedAttributes[i]
-               .attributeType == SA_NTF_VALUE_INT32) {
-        printf("[%d]: Id:%d Type:%d Value:%d\n", i,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .attributeId,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .attributeType,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .newAttributeValue.int32Val);
-      } else if (n->a_c_notif_ptr->changedAttributes[i]
-               .attributeType == SA_NTF_VALUE_UINT64) {
-        printf("[%d]: Id:%d Type:%d Value:%llu\n", i,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .attributeId,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .attributeType,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .newAttributeValue.uint64Val);
-      } else if (n->a_c_notif_ptr->changedAttributes[i]
-               .attributeType == SA_NTF_VALUE_INT64) {
-        printf("[%d]: Id:%d Type:%d Value:%lld\n", i,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .attributeId,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .attributeType,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .newAttributeValue.int64Val);
-      } else if (n->a_c_notif_ptr->changedAttributes[i]
-               .attributeType == SA_NTF_VALUE_FLOAT) {
-        printf("[%d]: Id:%d Type:%d Value:%f\n", i,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .attributeId,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .attributeType,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .newAttributeValue.floatVal);
-      } else if (n->a_c_notif_ptr->changedAttributes[i]
-               .attributeType == SA_NTF_VALUE_DOUBLE) {
-        printf("[%d]: Id:%d Type:%d Value:%f\n", i,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .attributeId,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .attributeType,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .newAttributeValue.doubleVal);
-      } else if (n->a_c_notif_ptr->changedAttributes[i]
-             .attributeType ==
-               SA_NTF_VALUE_BINARY ||
-           n->a_c_notif_ptr->changedAttributes[i]
-             .attributeType ==
-               SA_NTF_VALUE_LDAP_NAME) {
-        SaUint8T *binptr = NULL;
-        safassert(saNtfPtrValGet(
-            n->nHandle,
-            &n->a_c_notif_ptr->changedAttributes[i].newAttributeValue,
-            reinterpret_cast<void **>(&binptr), &numElem), SA_AIS_OK);
-        printf("[%d]: Id:%d Type:%d NumBytes:%u\n", i,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .attributeId,
-               n->a_c_notif_ptr->changedAttributes[i]
-             .attributeType,
-               numElem);
-        print_buf(binptr, numElem);
-      } else {
-        printf("Unsupported attribute type: %d\n",
-               n->a_c_notif_ptr->changedAttributes[i]
-             .attributeType);
-      }
-    }
+    print_new_attrs(n->nHandle, n->a_c_notif_ptr->changedAttributes,
+        n->a_c_notif_ptr->numAttributes);
+    print_old_attrs(n->nHandle, n->a_c_notif_ptr->changedAttributes,
+        n->a_c_notif_ptr->numAttributes);
    } else if (n->evType == SA_NTF_OBJECT_CREATION ||
         n->evType == SA_NTF_OBJECT_DELETION) {
      printf("Num attributes           : %d\n",
@@ -516,6 +547,132 @@ static SaBoolT is_equal_add_info(NotifData *n_exp, 
NotifData *n_rec) {
    return rc;
  }
+static SaBoolT is_equal_str_attr(SaNtfNotificationHandleT eHandle,
+    SaNtfNotificationHandleT rHandle,
+    SaNtfValueT* eVal,
+    SaNtfValueT* rVal) {
+  char *eStr = NULL;
+  char *rStr = NULL;
+  SaUint16T elen = 0;
+  SaUint16T rlen = 0;
+  SaBoolT res = SA_FALSE;
+  do {
+    SaAisErrorT rc = saNtfPtrValGet(
+        eHandle,
+        eVal,
+        reinterpret_cast<void **>(&eStr), &elen);
+    if (rc != SA_AIS_OK)
+      break;
+    rc = saNtfPtrValGet(
+        rHandle,
+        rVal,
+        reinterpret_cast<void **>(&rStr), &rlen);
+    if (rc != SA_AIS_OK)
+      break;
+    if (!strncmp(eStr, "immcfg", 6)) {
+      elen = rlen = 6;
+    }
+    if (elen == rlen && !strncmp(eStr, rStr, elen)) {
+      res = SA_TRUE;
+    }
+  } while (false);
+  return res;
+}
+
+static SaBoolT is_equal_scalar_attr(SaNtfAttributeChangeT* n_exp,
+    SaNtfAttributeChangeT* n_rec) {
+  SaBoolT rc = SA_FALSE;
+  switch (n_exp->attributeType) {
+  case SA_NTF_VALUE_UINT32: {
+    if (n_exp->newAttributeValue.uint32Val ==
+        n_rec->newAttributeValue.uint32Val) {
+      if (n_exp->oldAttributePresent) {
+        if (n_exp->oldAttributeValue.uint32Val ==
+            n_rec->oldAttributeValue.uint32Val) {
+          rc = SA_TRUE;
+        }
+      } else {
+        rc = SA_TRUE;
+      }
+    }
+    break;
+  }
+  case SA_NTF_VALUE_INT32: {
+    if (n_exp->newAttributeValue.int32Val ==
+        n_rec->newAttributeValue.int32Val) {
+      if (n_exp->oldAttributePresent) {
+        if (n_exp->oldAttributeValue.int32Val ==
+            n_rec->oldAttributeValue.int32Val) {
+          rc = SA_TRUE;
+        }
+      } else {
+        rc = SA_TRUE;
+      }
+    }
+    break;
+  }
+  case SA_NTF_VALUE_UINT64: {
+    if (n_exp->newAttributeValue.uint64Val ==
+        n_rec->newAttributeValue.uint64Val) {
+      if (n_exp->oldAttributePresent) {
+        if (n_exp->oldAttributeValue.uint64Val ==
+            n_rec->oldAttributeValue.uint64Val) {
+          rc = SA_TRUE;
+        }
+      } else {
+        rc = SA_TRUE;
+      }
+    }
+    break;
+  }
+  case SA_NTF_VALUE_INT64: {
+    if (n_exp->newAttributeValue.int64Val ==
+        n_rec->newAttributeValue.int64Val) {
+      if (n_exp->oldAttributePresent) {
+        if (n_exp->oldAttributeValue.int64Val ==
+            n_rec->oldAttributeValue.int64Val) {
+          rc = SA_TRUE;
+        }
+      } else {
+        rc = SA_TRUE;
+      }
+    }
+    break;
+  }
+  case SA_NTF_VALUE_FLOAT: {
+    if (n_exp->newAttributeValue.floatVal ==
+        n_rec->newAttributeValue.floatVal) {
+      if (n_exp->oldAttributePresent) {
+        if (n_exp->oldAttributeValue.floatVal ==
+            n_rec->oldAttributeValue.floatVal) {
+          rc = SA_TRUE;
+        }
+      } else {
+        rc = SA_TRUE;
+      }
+    }
+    break;
+  }
+  case SA_NTF_VALUE_DOUBLE: {
+    if (n_exp->newAttributeValue.doubleVal ==
+        n_rec->newAttributeValue.doubleVal) {
+      if (n_exp->oldAttributePresent) {
+        if (n_exp->oldAttributeValue.doubleVal ==
+            n_rec->oldAttributeValue.doubleVal) {
+          rc = SA_TRUE;
+        }
+      } else {
+        rc = SA_TRUE;
+      }
+    }
+    break;
+  }
+  default:
+    rc = SA_TRUE;  // for now
+  }
+  return rc;
+}
+
  /**
   * Check whether the attributes list data is equal between received and 
expected
   * attribute change notification.
@@ -525,8 +682,6 @@ static SaBoolT is_equal_ch_attr(const NotifData *n_exp,
    SaBoolT rc = SA_TRUE;
    int i = 0;
    int j = 0;
-  char *exp_str = NULL;
-  char *rec_str = NULL;
    SaUint16T exp_ln = 0;
    SaUint16T rec_ln = 0;
@@ -546,34 +701,20 @@ static SaBoolT is_equal_ch_attr(const NotifData *n_exp,
            elemVerified[j] == 0) {
          if (n_exp->a_c_notif_ptr->changedAttributes[j]
            .attributeType == SA_NTF_VALUE_STRING) {
-          safassert(saNtfPtrValGet(
-              n_exp->nHandle,
-              &n_exp->a_c_notif_ptr->changedAttributes[j].newAttributeValue,
-              reinterpret_cast<void **>(&exp_str), &exp_ln), SA_AIS_OK);
-          safassert(saNtfPtrValGet(
+          rc = is_equal_str_attr(n_exp->nHandle,
                n_rec->nHandle,
-              &n_rec->a_c_notif_ptr->changedAttributes[i].newAttributeValue,
-              reinterpret_cast<void **>(&rec_str), &rec_ln), SA_AIS_OK);
-          if (!strncmp(rec_str, "immcfg", 6)) {
-            exp_ln = 6;
-            rec_ln = 6;
-          }
-          if (exp_ln == rec_ln &&
-              !strncmp(exp_str, rec_str,
-                 exp_ln)) {
-            rc = SA_TRUE;
+              &n_exp->a_c_notif_ptr->changedAttributes[j].newAttributeValue,
+              &n_rec->a_c_notif_ptr->changedAttributes[i].newAttributeValue);
+          if (rc == SA_TRUE)
              break;
-          }
          } else if (n_exp->a_c_notif_ptr
                   ->changedAttributes[j]
                   .attributeType ==
               SA_NTF_VALUE_UINT32) {
-          if (n_exp->a_c_notif_ptr
-            ->changedAttributes[j]
-            .newAttributeValue.uint32Val ==
-              n_rec->a_c_notif_ptr
-            ->changedAttributes[i]
-            .newAttributeValue.uint32Val) {
+           if (is_equal_scalar_attr(&n_exp->a_c_notif_ptr
+              ->changedAttributes[j],
+              &n_rec->a_c_notif_ptr
+              ->changedAttributes[i])) {
              rc = SA_TRUE;
              break;
            }
@@ -638,12 +779,10 @@ static SaBoolT is_equal_ch_attr(const NotifData *n_exp,
                   ->changedAttributes[j]
                   .attributeType ==
               SA_NTF_VALUE_FLOAT) {
-          if (n_exp->a_c_notif_ptr
-            ->changedAttributes[j]
-            .newAttributeValue.floatVal ==
-              n_rec->a_c_notif_ptr
-            ->changedAttributes[i]
-            .newAttributeValue.floatVal) {
+          if (is_equal_scalar_attr(&n_exp->a_c_notif_ptr
+              ->changedAttributes[j],
+              &n_rec->a_c_notif_ptr
+              ->changedAttributes[i])) {
              rc = SA_TRUE;
              break;
            }
@@ -1162,7 +1301,9 @@ static SaAisErrorT set_attr_str(
          &n_exp->c_d_notif_ptr->objectAttributes[idx]
         .attributeValue);
      if (error == SA_AIS_OK) {
-      strcpy(reinterpret_cast<char *>(temp), attrValue);
+      //  strcpy(reinterpret_cast<char *>(temp), attrValue);
+      snprintf(reinterpret_cast<char *>(temp), strlen(attrValue) + 1,
+          "%s", attrValue);
        n_exp->c_d_notif_ptr->objectAttributes[idx]
            .attributeId = attrId;
        n_exp->c_d_notif_ptr->objectAttributes[idx]
@@ -1281,29 +1422,51 @@ static SaAisErrorT set_attr_extended_name(
  static SaAisErrorT set_attr_change_str(
      NotifData *n_exp, SaUint16T idx,
      SaNtfElementIdT attrId,
-    const char *newValue) {
+    const char *newValue,
+    SaBoolT oldAttrPresent = OLD_ATTR_PRESENT_DEFAULT,
+    const char *oldValue = NULL) {
    SaAisErrorT error = SA_AIS_OK;
    SaUint8T *temp = NULL;
- if (n_exp->a_c_notif_ptr != NULL) {
+  do {
+    if (n_exp->a_c_notif_ptr == NULL) {
+      error = SA_AIS_ERR_FAILED_OPERATION;
+      break;
+    }
+
      n_exp->a_c_notif_ptr->changedAttributes[idx]
-        .oldAttributePresent = SA_FALSE;
+        .oldAttributePresent = oldAttrPresent;
      error = saNtfPtrValAllocate(
          n_exp->nHandle, strlen(newValue) + 1, reinterpret_cast<void 
**>(&temp),
          &n_exp->a_c_notif_ptr->changedAttributes[idx]
         .newAttributeValue);
-    if (error == SA_AIS_OK) {
-      strcpy(reinterpret_cast<char *>(temp), newValue);
-      n_exp->a_c_notif_ptr->changedAttributes[idx]
-          .attributeId = attrId;
-      n_exp->a_c_notif_ptr->changedAttributes[idx]
-          .attributeType = SA_NTF_VALUE_STRING;
-    } else {
+    if (error != SA_AIS_OK) {
        error = SA_AIS_ERR_FAILED_OPERATION;
+      break;
      }
-  } else {
-    error = SA_AIS_ERR_FAILED_OPERATION;
-  }
+    //  strcpy(reinterpret_cast<char *>(temp), newValue);
+    snprintf(reinterpret_cast<char *>(temp),
+        strlen(newValue) + 1, "%s", newValue);
+    n_exp->a_c_notif_ptr->changedAttributes[idx]
+        .attributeId = attrId;
+    n_exp->a_c_notif_ptr->changedAttributes[idx]
+        .attributeType = SA_NTF_VALUE_STRING;
+    if (!oldAttrPresent || !oldValue)
+      break;
+    SaUint8T *otmp = NULL;
+    error = saNtfPtrValAllocate(
+        n_exp->nHandle, strlen(oldValue) + 1, reinterpret_cast<void **>(&otmp),
+        &n_exp->a_c_notif_ptr->changedAttributes[idx]
+       .oldAttributeValue);
+    if (error != SA_AIS_OK) {
+      error = SA_AIS_ERR_FAILED_OPERATION;
+      break;
+    }
+    //  strcpy(reinterpret_cast<char *>(otmp), oldValue);
+    snprintf(reinterpret_cast<char *>(otmp),
+        strlen(oldValue) + 1, "%s", oldValue);
+  } while (false);
+
    return error;
  }
@@ -1314,7 +1477,9 @@ static SaAisErrorT set_attr_change_buf(
      NotifData *n_exp, SaUint16T idx,
      SaNtfElementIdT attrId,
      SaNtfValueTypeT valType,
-    void *newValue) {
+    void *newValue,
+    SaBoolT oldAttrPresent = OLD_ATTR_PRESENT_DEFAULT,
+    void* oldValue = NULL) {
    SaAisErrorT error = SA_AIS_OK;
    SaUint16T numAlloc = (valType == SA_NTF_VALUE_BINARY)
           ? (reinterpret_cast<SaAnyT *>(newValue))->bufferSize
@@ -1324,25 +1489,48 @@ static SaAisErrorT set_attr_change_buf(
               ? (reinterpret_cast<SaAnyT *>(newValue))->bufferAddr
               : (reinterpret_cast<SaNameT *>(newValue))->value;
- if (n_exp->a_c_notif_ptr != NULL) {
+  do {
+    if (n_exp->a_c_notif_ptr == NULL) {
+      error = SA_AIS_ERR_FAILED_OPERATION;
+      break;
+    }
      n_exp->a_c_notif_ptr->changedAttributes[idx]
-        .oldAttributePresent = SA_FALSE;
+        .oldAttributePresent = oldAttrPresent;
      error = saNtfPtrValAllocate(
          n_exp->nHandle, numAlloc, reinterpret_cast<void **>(&temp),
          &n_exp->a_c_notif_ptr->changedAttributes[idx]
         .newAttributeValue);
-    if (error == SA_AIS_OK) {
-      memcpy(temp, srcPtr, numAlloc);
-      n_exp->a_c_notif_ptr->changedAttributes[idx]
-          .attributeId = attrId;
-      n_exp->a_c_notif_ptr->changedAttributes[idx]
-          .attributeType = valType;
-    } else {
+    if (error != SA_AIS_OK) {
        error = SA_AIS_ERR_FAILED_OPERATION;
+      break;
      }
-  } else {
-    error = SA_AIS_ERR_FAILED_OPERATION;
-  }
+    memcpy(temp, srcPtr, numAlloc);
+    n_exp->a_c_notif_ptr->changedAttributes[idx]
+        .attributeId = attrId;
+    n_exp->a_c_notif_ptr->changedAttributes[idx]
+        .attributeType = valType;
+
+    if (!oldAttrPresent || !oldValue)
+      break;
+    SaUint16T onumAlloc = (valType == SA_NTF_VALUE_BINARY)
+           ? (reinterpret_cast<SaAnyT *>(oldValue))->bufferSize
+           : (reinterpret_cast<SaNameT *>(oldValue))->length;
+    SaUint8T *otemp = NULL;
+    SaUint8T *osrcPtr = (valType == SA_NTF_VALUE_BINARY)
+               ? (reinterpret_cast<SaAnyT *>(oldValue))->bufferAddr
+               : (reinterpret_cast<SaNameT *>(oldValue))->value;
+    error = saNtfPtrValAllocate(
+        n_exp->nHandle, onumAlloc, reinterpret_cast<void **>(&otemp),
+        &n_exp->a_c_notif_ptr->changedAttributes[idx]
+       .oldAttributeValue);
+    if (error != SA_AIS_OK) {
+      error = SA_AIS_ERR_FAILED_OPERATION;
+      break;
+    }
+    memcpy(otemp, osrcPtr, onumAlloc);
+
+  } while (false);
+
    return error;
  }
@@ -1351,7 +1539,9 @@ static SaAisErrorT set_attr_change_extended_name(
      SaUint16T idx,
      SaNtfElementIdT attrId,
      SaNtfValueTypeT valType,
-    void *newValue) {
+    void *newValue,
+    SaBoolT oldAttrPresent = OLD_ATTR_PRESENT_DEFAULT,
+    void *oldValue = NULL) {
    assert(valType == SA_NTF_VALUE_LDAP_NAME);
    SaAisErrorT error = SA_AIS_OK;
    SaUint16T numAlloc = strlen(saAisNameBorrow(
@@ -1360,25 +1550,44 @@ static SaAisErrorT set_attr_change_extended_name(
    SaUint8T *srcPtr = reinterpret_cast<SaUint8T*>(const_cast<char*>(
        saAisNameBorrow(reinterpret_cast<SaNameT *>(newValue))));
- if (n_exp->a_c_notif_ptr != NULL) {
+  do {
+    if (n_exp->a_c_notif_ptr == NULL) {
+      error = SA_AIS_ERR_FAILED_OPERATION;
+      break;
+    }
      n_exp->a_c_notif_ptr->changedAttributes[idx]
-        .oldAttributePresent = SA_FALSE;
+        .oldAttributePresent = oldAttrPresent;
      error = saNtfPtrValAllocate(
          n_exp->nHandle, numAlloc, reinterpret_cast<void **>(&temp),
          &n_exp->a_c_notif_ptr->changedAttributes[idx]
         .newAttributeValue);
-    if (error == SA_AIS_OK) {
-      memcpy(temp, srcPtr, numAlloc);
-      n_exp->a_c_notif_ptr->changedAttributes[idx]
-          .attributeId = attrId;
-      n_exp->a_c_notif_ptr->changedAttributes[idx]
-          .attributeType = valType;
-    } else {
+    if (error != SA_AIS_OK) {
        error = SA_AIS_ERR_FAILED_OPERATION;
+      break;
      }
-  } else {
-    error = SA_AIS_ERR_FAILED_OPERATION;
-  }
+    memcpy(temp, srcPtr, numAlloc);
+    n_exp->a_c_notif_ptr->changedAttributes[idx]
+        .attributeId = attrId;
+    n_exp->a_c_notif_ptr->changedAttributes[idx]
+        .attributeType = valType;
+    if (!oldAttrPresent || !oldValue)
+      break;
+    SaUint16T onumAlloc = strlen(saAisNameBorrow(
+        reinterpret_cast<SaNameT *>(newValue)));
+    SaUint8T *otemp = nullptr;
+    SaUint8T *osrcPtr = reinterpret_cast<SaUint8T*>(const_cast<char*>(
+        saAisNameBorrow(reinterpret_cast<SaNameT *>(newValue))));
+    error = saNtfPtrValAllocate(
+        n_exp->nHandle, numAlloc, reinterpret_cast<void **>(&otemp),
+        &n_exp->a_c_notif_ptr->changedAttributes[idx]
+       .oldAttributeValue);
+    if (error != SA_AIS_OK) {
+      error = SA_AIS_ERR_FAILED_OPERATION;
+      break;
+    }
+    memcpy(otemp, osrcPtr, onumAlloc);
+  } while (false);
+
    return error;
  }
@@ -1390,31 +1599,57 @@ static SaAisErrorT set_attr_change_scalar(
      NotifData *n_exp, SaUint16T idx,
      SaNtfElementIdT attrId,
      SaNtfValueTypeT valType,
-    void *newValue) {
+    void *newValue,
+    SaBoolT oldAttrPresent = OLD_ATTR_PRESENT_DEFAULT,
+    void *oldValue = NULL) {
    SaAisErrorT error = SA_AIS_OK;
n_exp->a_c_notif_ptr->changedAttributes[idx].attributeId = attrId;
    n_exp->a_c_notif_ptr->changedAttributes[idx].attributeType = valType;
    n_exp->a_c_notif_ptr->changedAttributes[idx].oldAttributePresent =
-      SA_FALSE;
+      oldAttrPresent;
    if (valType == SA_NTF_VALUE_UINT32) {
      n_exp->a_c_notif_ptr->changedAttributes[idx]
          .newAttributeValue.uint32Val = *reinterpret_cast<SaUint32T 
*>(newValue);
+    if (oldAttrPresent && oldValue) {
+      n_exp->a_c_notif_ptr->changedAttributes[idx]
+        .oldAttributeValue.uint32Val = *reinterpret_cast<SaUint32T 
*>(oldValue);
+    }
    } else if (valType == SA_NTF_VALUE_INT32) {
      n_exp->a_c_notif_ptr->changedAttributes[idx]
          .newAttributeValue.int32Val = *reinterpret_cast<SaInt32T *>(newValue);
+    if (oldAttrPresent && oldValue) {
+      n_exp->a_c_notif_ptr->changedAttributes[idx]
+        .oldAttributeValue.int32Val = *reinterpret_cast<SaInt32T *>(oldValue);
+    }
    } else if (valType == SA_NTF_VALUE_UINT64) {
      n_exp->a_c_notif_ptr->changedAttributes[idx]
          .newAttributeValue.uint64Val = *reinterpret_cast<SaUint64T 
*>(newValue);
+    if (oldAttrPresent && oldValue) {
+      n_exp->a_c_notif_ptr->changedAttributes[idx]
+        .oldAttributeValue.uint64Val = *reinterpret_cast<SaUint64T 
*>(oldValue);
+    }
    } else if (valType == SA_NTF_VALUE_INT64) {
      n_exp->a_c_notif_ptr->changedAttributes[idx]
          .newAttributeValue.int64Val = *reinterpret_cast<SaInt64T *>(newValue);
+    if (oldAttrPresent && oldValue) {
+      n_exp->a_c_notif_ptr->changedAttributes[idx]
+        .oldAttributeValue.int64Val = *reinterpret_cast<SaInt64T *>(oldValue);
+    }
    } else if (valType == SA_NTF_VALUE_FLOAT) {
      n_exp->a_c_notif_ptr->changedAttributes[idx]
          .newAttributeValue.floatVal = *reinterpret_cast<SaFloatT *>(newValue);
+    if (oldAttrPresent && oldValue) {
+      n_exp->a_c_notif_ptr->changedAttributes[idx]
+        .oldAttributeValue.floatVal = *reinterpret_cast<SaFloatT *>(oldValue);
+    }
    } else if (valType == SA_NTF_VALUE_DOUBLE) {
      n_exp->a_c_notif_ptr->changedAttributes[idx]
          .newAttributeValue.doubleVal = *reinterpret_cast<SaDoubleT 
*>(newValue);
+    if (oldAttrPresent && oldValue) {
+      n_exp->a_c_notif_ptr->changedAttributes[idx]
+        .oldAttributeValue.doubleVal = *reinterpret_cast<SaDoubleT 
*>(oldValue);
+    }
    } else {
      error = SA_AIS_ERR_FAILED_OPERATION;
    }
@@ -3320,23 +3555,22 @@ void objectModifyTest_21(void) {
          SA_AIS_OK);
      safassert(set_add_info(&n_exp, 5, 5, "testFloatCfg"),
          SA_AIS_OK);
-    safassert(set_attr_change_str(&n_exp, 0, 0, "immcfg_xxx"),
-        SA_AIS_OK);
+    safassert(set_attr_change_str(&n_exp, 0, 0, "immcfg_xxx"), SA_AIS_OK);
      safassert(set_attr_change_str(&n_exp, 1, 1, "OsafNtfCmTestCFG"),
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 4, 4,
-             SA_NTF_VALUE_UINT32, &ivar),
+             SA_NTF_VALUE_UINT32, &ivar, SA_TRUE, (void*) &UINT32VAR1),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 5, 5,
-             SA_NTF_VALUE_FLOAT, &fvar),
+             SA_NTF_VALUE_FLOAT, &fvar, SA_TRUE, (void*) &FLOATVAR1),
          SA_AIS_OK);
if (!compare_notifs(&n_exp, &rec_notif_data)) {
@@ -3367,8 +3601,13 @@ void objectModifyTest_22(void) {
SaNameT var1 = {.length = sizeof(NAME2)};
    memcpy(var1.value, NAME2, sizeof(NAME2));
+  SaNameT var1old = {.length = sizeof(NAME1)};
+  memcpy(var1old.value, NAME1, sizeof(NAME1));
+
    SaAnyT var2 = {.bufferSize = sizeof(BUF2),
             .bufferAddr = const_cast<SaUint8T *>(BUF2)};
+  SaAnyT var2old = {.bufferSize = sizeof(BUF1),
+           .bufferAddr = const_cast<SaUint8T *>(BUF1)};
/* modify an object */
    snprintf(command, MAX_DATA, "immcfg -t 20 -a testNameCfg=%s "
@@ -3405,17 +3644,17 @@ void objectModifyTest_22(void) {
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
      safassert(set_attr_change_buf(&n_exp, 4, 4,
-                SA_NTF_VALUE_LDAP_NAME, &var1),
+                SA_NTF_VALUE_LDAP_NAME, &var1, SA_TRUE, &var1old),
          SA_AIS_OK);
      safassert(set_attr_change_buf(&n_exp, 5, 5, SA_NTF_VALUE_BINARY,
-                &var2),
+                &var2, SA_TRUE, &var2old),
          SA_AIS_OK);
if (!compare_notifs(&n_exp, &rec_notif_data)) {
@@ -3481,17 +3720,17 @@ void objectModifyTest_23(void) {
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 4, 4,
-             SA_NTF_VALUE_INT32, &addvar),
+             SA_NTF_VALUE_INT32, &addvar, SA_FALSE),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 5, 4,
-             SA_NTF_VALUE_INT32, &oldvar),
+             SA_NTF_VALUE_INT32, &oldvar, SA_TRUE, &oldvar),
          SA_AIS_OK);
if (!compare_notifs(&n_exp, &rec_notif_data)) {
@@ -3557,17 +3796,17 @@ void objectModifyTest_24(void) {
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 4, 4,
-             SA_NTF_VALUE_UINT32, &addvar),
+             SA_NTF_VALUE_UINT32, &addvar, SA_FALSE),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 5, 4,
-             SA_NTF_VALUE_UINT32, &oldvar),
+             SA_NTF_VALUE_UINT32, &oldvar, SA_TRUE, &oldvar),
          SA_AIS_OK);
if (!compare_notifs(&n_exp, &rec_notif_data)) {
@@ -3633,17 +3872,17 @@ void objectModifyTest_25(void) {
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 4, 4,
-             SA_NTF_VALUE_INT64, &addvar),
+             SA_NTF_VALUE_INT64, &addvar, SA_FALSE),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 5, 4,
-             SA_NTF_VALUE_INT64, &oldvar),
+             SA_NTF_VALUE_INT64, &oldvar, SA_TRUE, &oldvar),
          SA_AIS_OK);
if (!compare_notifs(&n_exp, &rec_notif_data)) {
@@ -3709,17 +3948,17 @@ void objectModifyTest_26(void) {
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 4, 4,
-             SA_NTF_VALUE_UINT64, &addvar),
+             SA_NTF_VALUE_UINT64, &addvar, SA_FALSE),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 5, 4,
-             SA_NTF_VALUE_UINT64, &oldvar),
+             SA_NTF_VALUE_UINT64, &oldvar, SA_TRUE, &oldvar),
          SA_AIS_OK);
if (!compare_notifs(&n_exp, &rec_notif_data)) {
@@ -3785,17 +4024,17 @@ void objectModifyTest_27(void) {
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 4, 4,
               SA_NTF_VALUE_FLOAT, &addvar),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 5, 4,
-             SA_NTF_VALUE_FLOAT, &oldvar),
+             SA_NTF_VALUE_FLOAT, &oldvar, SA_TRUE, &oldvar),
          SA_AIS_OK);
if (!compare_notifs(&n_exp, &rec_notif_data)) {
@@ -3861,17 +4100,17 @@ void objectModifyTest_28(void) {
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 4, 4,
               SA_NTF_VALUE_DOUBLE, &addvar),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 5, 4,
-             SA_NTF_VALUE_DOUBLE, &oldvar),
+             SA_NTF_VALUE_DOUBLE, &oldvar, SA_TRUE, &oldvar),
          SA_AIS_OK);
if (!compare_notifs(&n_exp, &rec_notif_data)) {
@@ -3936,17 +4175,17 @@ void objectModifyTest_29(void) {
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 4, 4,
               SA_NTF_VALUE_INT64, &addvar),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 5, 4,
-             SA_NTF_VALUE_INT64, &oldvar),
+             SA_NTF_VALUE_INT64, &oldvar, SA_TRUE, &oldvar),
          SA_AIS_OK);
if (!compare_notifs(&n_exp, &rec_notif_data)) {
@@ -4012,14 +4251,15 @@ void objectModifyTest_30(void) {
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
      safassert(set_attr_change_str(&n_exp, 4, 4, addvar), SA_AIS_OK);
-    safassert(set_attr_change_str(&n_exp, 5, 4, oldvar), SA_AIS_OK);
+    safassert(set_attr_change_str(&n_exp, 5, 4, oldvar,
+        SA_TRUE, oldvar), SA_AIS_OK);
if (!compare_notifs(&n_exp, &rec_notif_data)) {
        print_notif(&n_exp);
@@ -4086,14 +4326,14 @@ void objectModifyTest_31(void) {
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
      safassert(set_attr_change_buf(&n_exp, 4, 4,
-                SA_NTF_VALUE_LDAP_NAME, &oldvar),
+                SA_NTF_VALUE_LDAP_NAME, &oldvar, SA_TRUE, &oldvar),
          SA_AIS_OK);
      safassert(set_attr_change_buf(&n_exp, 5, 4,
                  SA_NTF_VALUE_LDAP_NAME, &addvar),
@@ -4167,14 +4407,14 @@ void objectModifyTest_32(void) {
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
      safassert(set_attr_change_buf(&n_exp, 4, 4, SA_NTF_VALUE_BINARY,
-                &oldvar),
+                &oldvar, SA_TRUE, &oldvar),
          SA_AIS_OK);
      safassert(set_attr_change_buf(&n_exp, 5, 4, SA_NTF_VALUE_BINARY,
                  &addvar),
@@ -4208,7 +4448,9 @@ void objectModifyTest_33(void) {
/* modify an object */
    SaStringT svar = STRINGVAR3;
+  SaStringT svarOld = STRINGVAR2;
    SaDoubleT dvar = DOUBLEVAR3;
+  SaDoubleT dvarOld = DOUBLEVAR2;
    snprintf(command, MAX_DATA,
      "immcfg -t 20 -a testStringCfg=%s -a testDoubleCfg=%lf %s",
      svar, dvar, DNTESTCFG);
@@ -4246,15 +4488,16 @@ void objectModifyTest_33(void) {
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
-    safassert(set_attr_change_str(&n_exp, 4, 4, svar), SA_AIS_OK);
+    safassert(set_attr_change_str(&n_exp, 4, 4, svar,
+        SA_TRUE, svarOld), SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 5, 5,
-             SA_NTF_VALUE_DOUBLE, &dvar),
+             SA_NTF_VALUE_DOUBLE, &dvar, SA_TRUE, &dvarOld),
          SA_AIS_OK);
if (!compare_notifs(&n_exp, &rec_notif_data)) {
@@ -4285,6 +4528,7 @@ void objectModifyTest_34(void) {
/* modify an object */
    SaTimeT tvar = TIMEVAR3;
+  SaTimeT tvarOld = TIMEVAR2;
    snprintf(command, MAX_DATA, "immcfg -t 20 -a testTimeCfg=%lld %s",
             (SaInt64T)tvar,  DNTESTCFG);
    assert(system(command) != -1);
@@ -4318,14 +4562,14 @@ void objectModifyTest_34(void) {
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 4, 4,
-             SA_NTF_VALUE_INT64, &tvar),
+             SA_NTF_VALUE_INT64, &tvar, SA_TRUE, &tvarOld),
          SA_AIS_OK);
if (!compare_notifs(&n_exp, &rec_notif_data)) {
@@ -4397,24 +4641,24 @@ void objectModifyTest_35(void) {
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
      safassert(set_attr_change_str(&n_exp, 4, 4, saddvar),
          SA_AIS_OK);
-    safassert(set_attr_change_str(&n_exp, 5, 4, soldvar),
+    safassert(set_attr_change_str(&n_exp, 5, 4, soldvar, SA_TRUE, soldvar),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 6, 5,
               SA_NTF_VALUE_INT32, &iaddvar),
          SA_AIS_OK);[M]
      safassert(set_attr_change_scalar(&n_exp, 7, 5,
-             SA_NTF_VALUE_INT32, &ioldvar1),
+             SA_NTF_VALUE_INT32, &ioldvar1, SA_TRUE, &ioldvar1),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 8, 5,
-             SA_NTF_VALUE_INT32, &ioldvar2),
+             SA_NTF_VALUE_INT32, &ioldvar2, SA_TRUE, &ioldvar2),
          SA_AIS_OK);
if (!compare_notifs(&n_exp, &rec_notif_data)) {
@@ -4486,19 +4730,19 @@ void objectModifyTest_36(void) {
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
-    safassert(set_attr_change_str(&n_exp, 4, 4, soldvar),
+    safassert(set_attr_change_str(&n_exp, 4, 4, soldvar, SA_TRUE, soldvar),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 5, 5,
-             SA_NTF_VALUE_INT32, &ivar1),
+             SA_NTF_VALUE_INT32, &ivar1, SA_TRUE, &ivar1),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 6, 5,
-             SA_NTF_VALUE_INT32, &ivar2),
+             SA_NTF_VALUE_INT32, &ivar2, SA_TRUE, &ivar2),
          SA_AIS_OK);
if (!compare_notifs(&n_exp, &rec_notif_data)) {
@@ -4611,44 +4855,49 @@ void objectModifyTest_37(void) {
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 4, 4,
-             SA_NTF_VALUE_INT32, &i32var1),
+             SA_NTF_VALUE_INT32, &i32var1, SA_TRUE, &i32var1),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 5, 4,
               SA_NTF_VALUE_INT32, &i32var11),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(
-            &n_exp, 6, 4, SA_NTF_VALUE_INT32, &i32var111),
+            &n_exp, 6, 4, SA_NTF_VALUE_INT32, &i32var111,
+            SA_TRUE, &i32var111),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(
              &n_exp, 7, 5, SA_NTF_VALUE_UINT32, &ui32var2),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(
-            &n_exp, 8, 5, SA_NTF_VALUE_UINT32, &ui32var22),
+            &n_exp, 8, 5, SA_NTF_VALUE_UINT32, &ui32var22,
+            SA_TRUE, &ui32var22),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(
-            &n_exp, 9, 5, SA_NTF_VALUE_UINT32, &ui32var222),
+            &n_exp, 9, 5, SA_NTF_VALUE_UINT32, &ui32var222,
+            SA_TRUE, &ui32var222),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 10, 6,
-             SA_NTF_VALUE_INT64, &i64var3),
+             SA_NTF_VALUE_INT64, &i64var3, SA_TRUE, &i64var3),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 11, 6,
-             SA_NTF_VALUE_INT64, &i64var33),
+             SA_NTF_VALUE_INT64, &i64var33, SA_TRUE, &i64var33),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(
              &n_exp, 12, 6, SA_NTF_VALUE_INT64, &i64var333),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(
-            &n_exp, 13, 7, SA_NTF_VALUE_UINT64, &ui64var4),
+            &n_exp, 13, 7, SA_NTF_VALUE_UINT64, &ui64var4,
+            SA_TRUE, &ui64var4),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(
-            &n_exp, 14, 7, SA_NTF_VALUE_UINT64, &ui64var44),
+            &n_exp, 14, 7, SA_NTF_VALUE_UINT64, &ui64var44,
+            SA_TRUE, &ui64var44),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(
              &n_exp, 15, 7, SA_NTF_VALUE_UINT64, &ui64var444),
@@ -4657,44 +4906,45 @@ void objectModifyTest_37(void) {
               SA_NTF_VALUE_FLOAT, &fvar5),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 17, 8,
-             SA_NTF_VALUE_FLOAT, &fvar55),
+             SA_NTF_VALUE_FLOAT, &fvar55, SA_TRUE, &fvar55),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 18, 8,
-             SA_NTF_VALUE_FLOAT, &fvar555),
+             SA_NTF_VALUE_FLOAT, &fvar555, SA_TRUE, &fvar555),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 19, 9,
               SA_NTF_VALUE_DOUBLE, &dvar66),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 20, 9,
-             SA_NTF_VALUE_DOUBLE, &dvar666),
+             SA_NTF_VALUE_DOUBLE, &dvar666, SA_TRUE, &dvar666),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 21, 10,
               SA_NTF_VALUE_INT64, &tvar77),
          SA_AIS_OK);
      safassert(set_attr_change_scalar(&n_exp, 22, 10,
-             SA_NTF_VALUE_INT64, &tvar777),
+             SA_NTF_VALUE_INT64, &tvar777, SA_TRUE, &tvar777),
          SA_AIS_OK);
      safassert(set_attr_change_str(&n_exp, 23, 11, svar8),
          SA_AIS_OK);
-    safassert(set_attr_change_str(&n_exp, 24, 11, svar888),
+    safassert(set_attr_change_str(&n_exp, 24, 11, svar888,
+        SA_TRUE, svar888),
          SA_AIS_OK);
      safassert(set_attr_change_buf(&n_exp, 25, 12,
                  SA_NTF_VALUE_LDAP_NAME, &nvar9),
          SA_AIS_OK);
      safassert(set_attr_change_buf(&n_exp, 26, 12,
-                SA_NTF_VALUE_LDAP_NAME, &nvar99),
+                SA_NTF_VALUE_LDAP_NAME, &nvar99, SA_TRUE, &nvar99),
          SA_AIS_OK);
      safassert(set_attr_change_buf(&n_exp, 27, 12,
-                SA_NTF_VALUE_LDAP_NAME, &nvar999),
+                SA_NTF_VALUE_LDAP_NAME, &nvar999, SA_TRUE, &nvar999),
          SA_AIS_OK);
      safassert(set_attr_change_buf(&n_exp, 28, 13,
                  SA_NTF_VALUE_BINARY, &avar10),
          SA_AIS_OK);
      safassert(set_attr_change_buf(&n_exp, 29, 13,
-                SA_NTF_VALUE_BINARY, &avar100),
+                SA_NTF_VALUE_BINARY, &avar100, SA_TRUE, &avar100),
          SA_AIS_OK);
      safassert(set_attr_change_buf(&n_exp, 30, 13,
-                SA_NTF_VALUE_BINARY, &avar1000),
+                SA_NTF_VALUE_BINARY, &avar1000, SA_TRUE, &avar1000),
          SA_AIS_OK);
if (!compare_notifs(&n_exp, &rec_notif_data)) {
@@ -4725,8 +4975,12 @@ void objectMultiCcbTest_38(void) {
    /* modify an object */
    SaUint32T var1 = 32000;
    SaInt32T var2 = -32000;
+  SaUint32T var1old = UINT32VAR2;
+  SaInt32T var2old = INT32VAR1;
    SaUint64T var3 = 64000;
    SaInt64T var4 = -64000;
+  SaUint64T var3old = UINT64VAR1;
+  SaInt64T var4old = INT64VAR1;
    SaImmHandleT omHandle = 0;
    SaImmAdminOwnerHandleT ownerHandle = 0;
    SaImmCcbHandleT immCcbHandle = 0;
@@ -4806,7 +5060,6 @@ void objectMultiCcbTest_38(void) {
        if (!rec_notif_data.populated)
          base::Sleep(base::kOneMillisecond);
      }
-
      NotifData n_exp;
      if (rec_notif_data.populated && noOfNotifs == 0) {
        safassert(set_ntf(&n_exp, SA_NTF_ATTRIBUTE_CHANGED,
@@ -4829,24 +5082,26 @@ void objectMultiCcbTest_38(void) {
        safassert(
            set_attr_change_str(&n_exp, 0, 0, "multiCcbOwner"),
            SA_AIS_OK);
-      safassert(set_attr_change_str(&n_exp, 1, 1,
-                  "OsafNtfCmTestCFG"),
+      safassert(set_attr_change_str(&n_exp, 1, 1, "OsafNtfCmTestCFG"),
            SA_AIS_OK);
        SaUint64T ccidVar = 3;
        safassert(set_attr_change_scalar(&n_exp, 2, 2,
                 SA_NTF_VALUE_UINT64,
-               &ccidVar),
+               &ccidVar, SA_TRUE, &ccidVar),
            SA_AIS_OK);
-      SaUint32T ccbLast = 0;
+      SaUint32T ccbLast = 0;  // 0 when uncomment other cases
        safassert(set_attr_change_scalar(&n_exp, 3, 3,
                 SA_NTF_VALUE_UINT32,
-               &ccbLast),
+               &ccbLast, SA_TRUE, &ccbLast),
            SA_AIS_OK);
+
        safassert(set_attr_change_scalar(
-              &n_exp, 4, 4, SA_NTF_VALUE_UINT32, &var1),
+              &n_exp, 4, 4, SA_NTF_VALUE_UINT32, &var1, SA_TRUE,
+              reinterpret_cast<void*>(&var1old)),
            SA_AIS_OK);
-      safassert(set_attr_change_scalar(
-              &n_exp, 5, 5, SA_NTF_VALUE_INT32, &var2),
+     safassert(set_attr_change_scalar(
+              &n_exp, 5, 5, SA_NTF_VALUE_INT32, &var2, SA_TRUE,
+              reinterpret_cast<void*>(&var2old)),
            SA_AIS_OK);
      } else if (rec_notif_data.populated && noOfNotifs == 1) {
        safassert(set_ntf(&n_exp, SA_NTF_ATTRIBUTE_CHANGED,
@@ -4869,24 +5124,27 @@ void objectMultiCcbTest_38(void) {
        safassert(
            set_attr_change_str(&n_exp, 0, 0, "multiCcbOwner"),
            SA_AIS_OK);
-      safassert(set_attr_change_str(&n_exp, 1, 1,
-                  "OsafNtfCmTestCFG"),
+      safassert(set_attr_change_str(&n_exp, 1, 1, "OsafNtfCmTestCFG"),
            SA_AIS_OK);
        SaUint64T ccidVar = 3;
        safassert(set_attr_change_scalar(&n_exp, 2, 2,
                 SA_NTF_VALUE_UINT64,
-               &ccidVar),
+               &ccidVar, SA_TRUE, &ccidVar),
            SA_AIS_OK);
        SaUint32T ccbLast = 1;
        safassert(set_attr_change_scalar(&n_exp, 3, 3,
                 SA_NTF_VALUE_UINT32,
-               &ccbLast),
+               &ccbLast, SA_TRUE, &ccbLast),
            SA_AIS_OK);
        safassert(set_attr_change_scalar(
-              &n_exp, 4, 4, SA_NTF_VALUE_UINT64, &var3),
+              &n_exp, 4, 4, SA_NTF_VALUE_UINT64, &var3,
+              SA_TRUE,
+              reinterpret_cast<void*>(&var3old)),
            SA_AIS_OK);
        safassert(set_attr_change_scalar(
-              &n_exp, 5, 5, SA_NTF_VALUE_INT64, &var4),
+              &n_exp, 5, 5, SA_NTF_VALUE_INT64, &var4,
+              SA_TRUE,
+              reinterpret_cast<void*>(&var4old)),
            SA_AIS_OK);
      } else {
        error = SA_AIS_ERR_FAILED_OPERATION;
@@ -5057,25 +5315,24 @@ void objectMultiCcbTest_39(void) {
        safassert(
            set_attr_change_str(&n_exp, 0, 0, "multiCcbOwner"),
            SA_AIS_OK);
-      safassert(set_attr_change_str(&n_exp, 1, 1,
-                  "OsafNtfCmTestCFG"),
+      safassert(set_attr_change_str(&n_exp, 1, 1, "OsafNtfCmTestCFG"),
            SA_AIS_OK);
        SaUint64T ccidVar = 3;
        safassert(set_attr_change_scalar(&n_exp, 2, 2,
                 SA_NTF_VALUE_UINT64,
-               &ccidVar),
+               &ccidVar, SA_TRUE, &ccidVar),
            SA_AIS_OK);
        SaUint32T ccbLast = 0;
        safassert(set_attr_change_scalar(&n_exp, 3, 3,
                 SA_NTF_VALUE_UINT32,
-               &ccbLast),
+               &ccbLast, SA_TRUE, &ccbLast),
            SA_AIS_OK);
        safassert(set_attr_change_scalar(
                &n_exp, 4, 4, SA_NTF_VALUE_UINT32, &var1),
            SA_AIS_OK);
        safassert(set_attr_change_scalar(&n_exp, 5, 4,
                 SA_NTF_VALUE_UINT32,
-               &oldvar1),
+               &oldvar1, SA_TRUE, &oldvar1),
            SA_AIS_OK);
      } else if (rec_notif_data.populated && noOfNotifs == 1) {
        safassert(set_ntf(&n_exp, SA_NTF_ATTRIBUTE_CHANGED,
@@ -5096,21 +5353,20 @@ void objectMultiCcbTest_39(void) {
        safassert(
            set_attr_change_str(&n_exp, 0, 0, "multiCcbOwner"),
            SA_AIS_OK);
-      safassert(set_attr_change_str(&n_exp, 1, 1,
-                  "OsafNtfCmTestCFG"),
+      safassert(set_attr_change_str(&n_exp, 1, 1, "OsafNtfCmTestCFG"),
            SA_AIS_OK);
        SaUint64T ccidVar = 3;
        safassert(set_attr_change_scalar(&n_exp, 2, 2,
                 SA_NTF_VALUE_UINT64,
-               &ccidVar),
+               &ccidVar, SA_TRUE, &ccidVar),
            SA_AIS_OK);
        SaUint32T ccbLast = 0;
        safassert(set_attr_change_scalar(&n_exp, 3, 3,
                 SA_NTF_VALUE_UINT32,
-               &ccbLast),
+               &ccbLast, SA_TRUE, &ccbLast),
            SA_AIS_OK);
        safassert(set_attr_change_scalar(
-              &n_exp, 4, 4, SA_NTF_VALUE_INT32, &var2),
+              &n_exp, 4, 4, SA_NTF_VALUE_INT32, &var2, SA_TRUE),
            SA_AIS_OK);
      } else if (rec_notif_data.populated && noOfNotifs == 2) {
        /*
@@ -5142,31 +5398,30 @@ void objectMultiCcbTest_39(void) {
        safassert(
            set_attr_change_str(&n_exp, 0, 0, "multiCcbOwner"),
            SA_AIS_OK);
-      safassert(set_attr_change_str(&n_exp, 1, 1,
-                  "OsafNtfCmTestCFG"),
+      safassert(set_attr_change_str(&n_exp, 1, 1, "OsafNtfCmTestCFG"),
            SA_AIS_OK);
        SaUint64T ccidVar = 3;
        safassert(set_attr_change_scalar(&n_exp, 2, 2,
                 SA_NTF_VALUE_UINT64,
-               &ccidVar),
+               &ccidVar, SA_TRUE, &ccidVar),
            SA_AIS_OK);
        SaUint32T ccbLast =
            1; /* Last notification of the CCB */
        safassert(set_attr_change_scalar(&n_exp, 3, 3,
                 SA_NTF_VALUE_UINT32,
-               &ccbLast),
+               &ccbLast, SA_TRUE, &ccbLast),
            SA_AIS_OK);
        safassert(set_attr_change_scalar(&n_exp, 4, 6,
                 SA_NTF_VALUE_FLOAT,
-               &oldvar6),
+               &oldvar6, SA_TRUE, &var6),
            SA_AIS_OK);
        safassert(set_attr_change_scalar(&n_exp, 5, 6,
                 SA_NTF_VALUE_FLOAT,
-               &oldvar66),
+               &oldvar66, SA_TRUE, &oldvar66),
            SA_AIS_OK);
        safassert(set_attr_change_scalar(&n_exp, 6, 7,
                 SA_NTF_VALUE_DOUBLE,
-               &oldvar5),
+               &oldvar5, SA_TRUE, &oldvar5),
            SA_AIS_OK);
} else {
@@ -5966,6 +6221,11 @@ void objectModifyTest_3506(void) {
SaAnyT var2 = {.bufferSize = sizeof(BUF2),
             .bufferAddr = const_cast<SaUint8T *>(BUF2)};
+  SaNameT var1old;
+  saAisNameLend((SaConstStringT)&extended_name_string_01,
+          &var1old);
+  SaAnyT var2old = {.bufferSize = sizeof(BUF1),
+           .bufferAddr = const_cast<SaUint8T *>(BUF1)};
/* modify an object */
    snprintf(command, MAX_DATA, "immcfg -t 20 -a testNameCfg=%s"
@@ -6002,17 +6262,19 @@ void objectModifyTest_3506(void) {
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
      safassert(set_attr_change_extended_name(
-            &n_exp, 4, 4, SA_NTF_VALUE_LDAP_NAME, &var1),
+            &n_exp, 4, 4, SA_NTF_VALUE_LDAP_NAME, &var1,
+            SA_TRUE,
+            reinterpret_cast<void*>(&var1old)),
          SA_AIS_OK);
      safassert(set_attr_change_buf(&n_exp, 5, 5, SA_NTF_VALUE_BINARY,
-                &var2),
+                &var2, SA_TRUE, &var2old),
          SA_AIS_OK);
if (!compare_notifs(&n_exp, &rec_notif_data)) {
@@ -6080,14 +6342,14 @@ void objectModifyTest_3507(void) {
          SA_AIS_OK);
      SaUint64T ccidVar = 3;
      safassert(set_attr_change_scalar(&n_exp, 2, 2,
-             SA_NTF_VALUE_UINT64, &ccidVar),
+             SA_NTF_VALUE_UINT64, &ccidVar, SA_TRUE, &ccidVar),
          SA_AIS_OK);
      SaUint32T ccbLast = 1;
      safassert(set_attr_change_scalar(&n_exp, 3, 3,
-             SA_NTF_VALUE_UINT32, &ccbLast),
+             SA_NTF_VALUE_UINT32, &ccbLast, SA_TRUE, &ccbLast),
          SA_AIS_OK);
      safassert(set_attr_change_extended_name(
-            &n_exp, 4, 4, SA_NTF_VALUE_LDAP_NAME, &oldvar),
+            &n_exp, 4, 4, SA_NTF_VALUE_LDAP_NAME, &oldvar, SA_TRUE, &oldvar),
          SA_AIS_OK);
      safassert(set_attr_change_extended_name(
              &n_exp, 5, 4, SA_NTF_VALUE_LDAP_NAME, &addvar),
@@ -6190,7 +6452,7 @@ __attribute__((constructor)) static void 
ntf_imcn_constructor(void) {
     */
    if (stat("//tmp//ntfsv_test_classes.xml", &buf) != 0) {
      rc = system(
-        "find / -name ntfsv_test_classes.xml > /tmp/ntftemp.txt");
+        "find /srv -name ntfsv_test_classes.xml > /tmp/ntftemp.txt");
      if (rc == 0) {
        FILE *f = fopen("/tmp/ntftemp.txt", "r");
        if (f != NULL) {
@@ -6198,7 +6460,8 @@ __attribute__((constructor)) static void 
ntf_imcn_constructor(void) {
          if (fgets(line, 80, f) != NULL) {
            if (strstr(line, ".xml") != NULL) {
              char cp_cmd[80];
-            snprintf(cp_cmd, sizeof(cp_cmd), "cp ");
+            char* pcmd = cp_cmd;
+            pcmd += snprintf(cp_cmd, sizeof(cp_cmd), "cp ");
              if ((strlen(line) - 1) > (sizeof(cp_cmd) - sizeof("cp "))) {
                printf("line: %s too long", line);
                if (fclose(f) != 0)
@@ -6206,7 +6469,8 @@ __attribute__((constructor)) static void 
ntf_imcn_constructor(void) {
                return;
              }
              line[strlen(line)] = '\0';
-            strcat(cp_cmd, line);  // don't add newline
+            snprintf(pcmd,
+                strlen(line), "%s", line);  // don't add newline
              strncat(cp_cmd, " /tmp/.", 80 - strlen(cp_cmd));
              rc = system(cp_cmd);
            } else {
diff --git a/src/ntf/apitest/tet_ntf_common.cc 
b/src/ntf/apitest/tet_ntf_common.cc
index 6bb1ff72f..dbe153003 100644
--- a/src/ntf/apitest/tet_ntf_common.cc
+++ b/src/ntf/apitest/tet_ntf_common.cc
@@ -1444,3 +1444,88 @@ void fprintf_p(FILE *f, const char *format, ...) {
    va_end(argptr);
    fflush(f);
  }
+
+static void print_hex_ascii_line(const unsigned char *payload,
+    int len, int offset) {
+    int i;
+    const unsigned char *ch;
+
+    // offset
+    printf("%05d   ", offset);
+
+    // hex
+    ch = payload;
+    for (i = 0; i < len; ++i) {
+        printf("%02x ", *ch);
+        ++ch;
+        // print extra space after 8th byte for visual aid
+        if (i == 7)
+            printf(" ");
+    }
+    // print space to handle line less than 8 bytes
+    if (len < 8)
+        printf(" ");
+
+    // fill hex gap with spaces if not full line
+    int gap;
+    if (len < 16) {
+        gap = 16 - len;
+        for (i = 0; i < gap; ++i) {
+            printf("   ");
+        }
+    }
+    printf("   ");
+
+    // ascii (if printable)
+    ch = payload;
+    for (i = 0; i < len; ++i) {
+        if (isprint(*ch))
+            printf("%c", *ch);
+        else
+            printf(".");
+        ++ch;
+    }
+
+    printf("\n");
+
+    return;
+}
+
+void print_mem(const unsigned char *mem, int len) {
+    int len_rem = len;
+    int line_width = 16;          // number of bytes per line
+    int line_len;
+    int offset = 0;               // zero-based offset counter
+
+    if (len <= 0 || !mem)
+        return;
+    const unsigned char *ch = mem;
+
+    // data fits on one line
+    if (len <= line_width) {
+        print_hex_ascii_line(ch, len, offset);
+        return;
+    }
+
+    // data spans multiple lines
+    for ( ;; ) {
+        // compute current line length
+        line_len = line_width % len_rem;
+        // print line
+        print_hex_ascii_line(ch, line_len, offset);
+        // compute total remaining /
+        len_rem = len_rem - line_len;
+        // shift pointer to remaining bytes to print
+        ch = ch + line_len;
+        // add offset
+        offset = offset + line_width;
+        // check if we have line width chars or less
+        if (len_rem <= line_width) {
+            // print last line and get out
+            print_hex_ascii_line(ch, len_rem, offset);
+            break;
+        }
+    }
+    return;
+}
+
diff --git a/src/ntf/apitest/tet_ntf_common.h b/src/ntf/apitest/tet_ntf_common.h
index 7a8912aac..52d3bd4ba 100644
--- a/src/ntf/apitest/tet_ntf_common.h
+++ b/src/ntf/apitest/tet_ntf_common.h
@@ -384,6 +384,8 @@ extern "C" {
extern void saAisNameLend(SaConstStringT value, SaNameT *name);
  extern SaConstStringT saAisNameBorrow(const SaNameT *name);
+extern void print_mem(const unsigned char *mem, int len);
+
#ifdef __cplusplus
  }
diff --git a/src/ntf/ntfimcnd/ntfimcn_common.c 
b/src/ntf/ntfimcnd/ntfimcn_common.c
new file mode 100755
index 000000000..c257aa95a
--- /dev/null
+++ b/src/ntf/ntfimcnd/ntfimcn_common.c
@@ -0,0 +1,398 @@
+/*      -*- OpenSAF  -*-
+ *
+ * (C) Copyright 2013 The OpenSAF Foundation
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "ntfimcn_common.h"
+#include "osaf/immutil/immutil.h"
+#include "ntfimcn_main.h"
+
+#include "base/logtrace.h"
+
+const int DBG_MX_LEN = 512;
+
+extern ntfimcn_cb_t ntfimcn_cb; /* See ntfimcn_main.c */
+
+const char *CcbUtilOperationType_Str[] = { "CCBUTIL_CREATE", "CCBUTIL_DELETE",
+    "CCBUTIL_MODIFY" };
+
+void dbg_format_attr_value(SaImmValueTypeT attrValueType,
+    SaImmAttrValueT *attrValue, char *outbuffer)
+{
+  switch (attrValueType) {
+  case SA_IMM_ATTR_SAINT32T:
+    snprintf(outbuffer, DBG_MX_LEN, "%d (0x%x)", *((SaInt32T*) attrValue),
+        *((SaInt32T*) attrValue));
+    break;
+  case SA_IMM_ATTR_SAUINT32T:
+    snprintf(outbuffer, DBG_MX_LEN, "%u (0x%x)", *((SaUint32T*) attrValue),
+        *((SaUint32T*) attrValue));
+    break;
+  case SA_IMM_ATTR_SAINT64T:
+    snprintf(outbuffer, DBG_MX_LEN, "%lld (0x%llx)", *((SaInt64T*) attrValue),
+        *((SaInt64T*) attrValue));
+    break;
+  case SA_IMM_ATTR_SAUINT64T:
+    snprintf(outbuffer, DBG_MX_LEN, "%llu (0x%llx)", *((SaUint64T*) attrValue),
+        *((SaUint64T*) attrValue));
+    break;
+  case SA_IMM_ATTR_SAFLOATT:
+    snprintf(outbuffer, DBG_MX_LEN, "%.8g", *((SaFloatT*) attrValue));
+    break;
+  case SA_IMM_ATTR_SADOUBLET:
+    snprintf(outbuffer, DBG_MX_LEN, "%.17g", *((SaDoubleT*) attrValue));
+    break;
+  case SA_IMM_ATTR_SANAMET: {
+    SaNameT *myNameT = (SaNameT*) attrValue;
+    snprintf(outbuffer, DBG_MX_LEN, "%s (%zu)", saAisNameBorrow(myNameT),
+        strlen(saAisNameBorrow(myNameT)));
+    break;
+  }
+  case SA_IMM_ATTR_SASTRINGT:
+    snprintf(outbuffer, DBG_MX_LEN, "%s", *((char**) attrValue));
+    break;
+  case SA_IMM_ATTR_SAANYT: {
+    SaAnyT *anyp = (SaAnyT*) attrValue;
+    char *cur = outbuffer;
+    if (anyp->bufferSize) {
+      cur += snprintf(cur, DBG_MX_LEN, "%s", "0x");
+      for (unsigned int i = 0; i < anyp->bufferSize; ++i) {
+        if (((int) anyp->bufferAddr[i]) < 0x10) {
+          cur += snprintf(cur, DBG_MX_LEN, "%s", "0");
+        }
+        cur += snprintf(cur, DBG_MX_LEN, "%x", (int) anyp->bufferAddr[i]);
+      }
+    }
+    snprintf(cur, DBG_MX_LEN, " size(%u) ",
+        (unsigned int) anyp->bufferSize);
+    break;
+  }
+
+  default:
+    snprintf(outbuffer, DBG_MX_LEN, "%s", "Unknown ");
+    break;
+  }
+
+}
+
+char* dbg_get_attr_type_name(SaImmValueTypeT attrValueType)
+{
+  switch (attrValueType) {
+  case SA_IMM_ATTR_SAINT32T:
+    return "SA_INT32_T";
+    break;
+  case SA_IMM_ATTR_SAUINT32T:
+    return "SA_UINT32_T";
+    break;
+  case SA_IMM_ATTR_SAINT64T:
+    return "SA_INT64_T";
+    break;
+  case SA_IMM_ATTR_SAUINT64T:
+    return "SA_UINT64_T";
+    break;
+  case SA_IMM_ATTR_SATIMET:
+    return "SA_TIME_T";
+    break;
+  case SA_IMM_ATTR_SANAMET:
+    return "SA_NAME_T";
+    break;
+  case SA_IMM_ATTR_SAFLOATT:
+    return "SA_FLOAT_T";
+    break;
+  case SA_IMM_ATTR_SADOUBLET:
+    return "SA_DOUBLE_T";
+    break;
+  case SA_IMM_ATTR_SASTRINGT:
+    return "SA_STRING_T";
+    break;
+  case SA_IMM_ATTR_SAANYT:
+    return "SA_ANY_T";
+    break;
+  default:
+    return "Unknown";
+    break;
+  }
+}
+
+void dbg_trace_attr_mods(const SaImmAttrModificationT_2 **attrMods)
+{
+  TRACE_ENTER();
+  int i = 0;
+  const SaImmAttrModificationT_2 *attrmod;
+  for (i = 0; (attrmod = attrMods[i]) != NULL; ++i) {
+     dbg_trace_attr(&attrmod->modAttr);
+  }
+  TRACE_LEAVE2("No of attr printed = %d", i);
+}
+
+void dbg_trace_attr(const SaImmAttrValuesT_2 *attr)
+{
+  char buff[DBG_MX_LEN];
+  char *pbuff = buff;
+  TRACE("%s, %s", attr->attrName,
+      dbg_get_attr_type_name(attr->attrValueType));
+  if (attr->attrValuesNumber > 0) {
+    for (unsigned int j = 0; j < attr->attrValuesNumber; ++j) {
+      dbg_format_attr_value(attr->attrValueType,
+          attr->attrValues[j], pbuff);
+      TRACE("%s", pbuff);
+    }
+  } else {
+    TRACE("<Empty>");
+  }
+}
+
+void dbg_trace_attrs(const SaImmAttrValuesT_2 **attrs)
+{
+  TRACE_ENTER();
+  int i = 0;
+  const SaImmAttrValuesT_2 *attr;
+  do {
+    if (attrs == NULL) {
+      TRACE("Attempt to trace NULL SaImmAttrValuesT_2*");
+      break;
+    }
+    for (i = 0; (attr = attrs[i]) != NULL; ++i) {
+      dbg_trace_attr(attr);
+    }
+  } while (SA_FALSE);
+  TRACE_LEAVE2("No of attr printed = %d", i);
+}
+
+SaAisErrorT get_current_attrs(const SaNameT *objectName,
+    const SaImmAttrModificationT_2 **attrMods,
+    SaImmAttrValuesT_2 ***curAttr,
+    SaBoolT copy, SaBoolT verbose)
+{
+  TRACE_ENTER();
+  SaAisErrorT rc = SA_AIS_OK;
+  // There is no new attribute modifications
+  if (attrMods == NULL) {
+    *curAttr = NULL;
+    return SA_AIS_ERR_INVALID_PARAM;
+  }
+  int len;
+  for (len = 0; attrMods[len] != NULL; ++len) ;
+  SaImmAttrNameT *attrNames = calloc((len + 1), sizeof(SaImmAttrNameT));
+  if (attrNames == NULL) {
+    *curAttr = NULL;
+    return SA_AIS_ERR_NO_MEMORY;
+  }
+  for (int i = 0; i < len; ++i) {
+    attrNames[i] = attrMods[i]->modAttr.attrName;
+  }
+  attrNames[len] = NULL;
+  // Get current attributes for the given attribute names
+  SaImmAttrValuesT_2 **resAttr;
+  rc = immutil_saImmOmAccessorGet_2(ntfimcn_cb.immAccessorHandle,
+      objectName, attrNames, &resAttr);
+  if (SA_AIS_OK == rc) {
+    if (copy) {
+      *curAttr = imm_attributes_cpy((const SaImmAttrValuesT_2**) resAttr);
+    } else {
+      *curAttr = resAttr;
+    }
+    if (verbose) {
+      TRACE("len = %d", len);
+      for (int i = 0; i < len; ++i) {
+        TRACE("attrNames[%d] = %s", i, attrNames[i]);
+      }
+      dbg_trace_attrs((const SaImmAttrValuesT_2**) *curAttr);
+    }
+  } else {
+    TRACE("immutil_saImmOmAccessorGet_2 failed rc = %u", rc);
+  }
+  free(attrNames);
+  TRACE_LEAVE2("rc = %u", rc);
+  return rc;
+}
+
+void free_imcnUserData(void *data)
+{
+  if (data == NULL)
+    return;
+  ImcnUserData_t* imcnData = (ImcnUserData_t*) data;
+  free_imm_attrs(imcnData->currAttr);
+  free(imcnData);
+}
+
+ImcnUserData_t* create_imcnUserData()
+{
+  ImcnUserData_t *data = malloc(sizeof(ImcnUserData_t));
+  if (data != NULL) {
+    data->currAttrAvailable = SA_FALSE;
+    data->errorCode = SA_AIS_ERR_UNAVAILABLE;
+    data->currAttr = NULL;
+  }
+  return data;
+}
+
+static size_t imm_attr_value_size(SaImmValueTypeT type)
+{
+  size_t valueSize = 0;
+
+  switch (type) {
+  case SA_IMM_ATTR_SAINT32T:
+    valueSize = sizeof(SaInt32T);
+    break;
+  case SA_IMM_ATTR_SAUINT32T:
+    valueSize = sizeof(SaUint32T);
+    break;
+  case SA_IMM_ATTR_SAINT64T:
+    valueSize = sizeof(SaInt64T);
+    break;
+  case SA_IMM_ATTR_SAUINT64T:
+    valueSize = sizeof(SaUint64T);
+    break;
+  case SA_IMM_ATTR_SATIMET:
+    valueSize = sizeof(SaTimeT);
+    break;
+  case SA_IMM_ATTR_SANAMET:
+    valueSize = sizeof(SaNameT);
+    break;
+  case SA_IMM_ATTR_SAFLOATT:
+    valueSize = sizeof(SaFloatT);
+    break;
+  case SA_IMM_ATTR_SADOUBLET:
+    valueSize = sizeof(SaDoubleT);
+    break;
+  case SA_IMM_ATTR_SASTRINGT:
+    valueSize = sizeof(SaStringT);
+    break;
+  case SA_IMM_ATTR_SAANYT:
+    valueSize = sizeof(SaAnyT);
+    break;
+  }
+  return valueSize;
+
+}
+
+static void imm_attr_cpy(SaImmAttrValuesT_2 **dest,
+    const SaImmAttrValuesT_2 *src)
+{
+  SaImmAttrValuesT_2 *tdest =
+      (SaImmAttrValuesT_2*) calloc(1, sizeof(SaImmAttrValuesT_2));
+  tdest->attrName = strdup(src->attrName);
+
+  tdest->attrValueType = src->attrValueType;
+  tdest->attrValuesNumber = src->attrValuesNumber;
+  SaUint32T count = src->attrValuesNumber;
+  size_t valSize = imm_attr_value_size(src->attrValueType);
+  if (src->attrValues == NULL) {
+     *dest = tdest;
+    return;
+  }
+  tdest->attrValues = (SaImmAttrValueT*) malloc(
+      sizeof(SaImmAttrValueT) * count);
+
+  for (unsigned int i = 0; i < count; ++i) {
+    if (src->attrValues[i] == NULL) {
+      tdest->attrValues[i] = NULL;
+      continue;
+    }
+    tdest->attrValues[i] = malloc(valSize);
+    switch (src->attrValueType) {
+    case SA_IMM_ATTR_SASTRINGT: {
+      *((SaStringT*) tdest->attrValues[i]) =
+          strdup(*((SaStringT*) src->attrValues[i]));
+      break;
+    }
+    case SA_IMM_ATTR_SANAMET: {
+      SaNameT* nameSrc = (SaNameT*) src->attrValues[i];
+      SaNameT* nameDest = (SaNameT*) tdest->attrValues[i];
+      osaf_extended_name_alloc(osaf_extended_name_borrow(nameSrc), nameDest);
+      break;
+    }
+    case SA_IMM_ATTR_SAANYT: {
+      SaAnyT *anySrc = (SaAnyT*) src->attrValues[i];
+      SaAnyT *anyDest = (SaAnyT*) tdest->attrValues[i];
+      anyDest->bufferSize = anySrc->bufferSize;
+      if (anyDest->bufferSize) {
+        anyDest->bufferAddr = (SaUint8T*) malloc(anyDest->bufferSize);
+        memcpy(anyDest->bufferAddr, anySrc->bufferAddr, anyDest->bufferSize);
+      }
+      else {
+        anyDest->bufferAddr = NULL;
+      }
+      break;
+    }
+    default:
+      memcpy(tdest->attrValues[i], src->attrValues[i], valSize);
+      break;
+    }
+  }
+  *dest = tdest;
+}
+
+SaImmAttrValuesT_2** imm_attributes_cpy(const SaImmAttrValuesT_2 **src)
+{
+  // Return if there is no source
+  if (src == NULL) {
+    TRACE("src is null");
+    return NULL;
+  }
+  // Return if the source is just an array of NULL
+  int len = 0;
+  while (src[len] != NULL) ++len;
+  if (!len) {
+    TRACE("src length is null");
+    return NULL;
+  }
+  SaImmAttrValuesT_2 **attr =
+      (SaImmAttrValuesT_2**) malloc((len + 1) * sizeof(SaImmAttrValuesT_2*));
+  if (attr == NULL) {
+    TRACE("Failed to allocate memory");
+    return NULL;
+  }
+  // Deep clone the source to destination
+  for (int i = 0; i < len; ++i) {
+    imm_attr_cpy(&attr[i], src[i]);
+  }
+  attr[len] = NULL;
+  return attr;
+}
+
+void free_imm_attrs(SaImmAttrValuesT_2 **attrs)
+{
+  if (attrs == NULL)
+    return;
+  SaImmAttrValuesT_2 *attr;
+  SaImmAttrValueT value;
+  for (int i = 0; (attr = attrs[i]) != NULL; ++i) {
+    free(attr->attrName);
+    if (attr->attrValues == NULL) {
+      continue;
+    }
+    for (unsigned int j = 0; j < attr->attrValuesNumber; ++j) {
+      value = attr->attrValues[j];
+      if (value == NULL) {
+        continue;
+      }
+      if (attr->attrValueType == SA_IMM_ATTR_SASTRINGT) {
+        free(*((SaStringT*) value));
+      } else if (attr->attrValueType == SA_IMM_ATTR_SANAMET) {
+        osaf_extended_name_free((SaNameT*) value);
+      } else if (attr->attrValueType == SA_IMM_ATTR_SAANYT) {
+        free(((SaAnyT*) value)->bufferAddr);
+      }
+      free(value);
+    }
+    free(attr->attrValues);
+    free(attr);
+  }
+}
diff --git a/src/ntf/ntfimcnd/ntfimcn_common.h 
b/src/ntf/ntfimcnd/ntfimcn_common.h
new file mode 100755
index 000000000..ac5b8309e
--- /dev/null
+++ b/src/ntf/ntfimcnd/ntfimcn_common.h
@@ -0,0 +1,123 @@
+/*      -*- OpenSAF  -*-
+ *
+ * (C) Copyright 2013 The OpenSAF Foundation
+ *
+ * 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 NTF_NTFIMCND_NTFIMCN_COMMON_H_
+#define NTF_NTFIMCND_NTFIMCN_COMMON_H_
+
+#include <saNtf.h>
+#include <saImmOi.h>
+#include <saImmOm.h>
+#include "base/osaf_extended_name.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Format IMM Attribute Values
+  *
+ * @param attrValueType[in]
+ * @param *attrValue[in]
+ * @param *outbuffer[out]
+ */
+void dbg_format_attr_value(SaImmValueTypeT attrValueType,
+    SaImmAttrValueT *attrValue, char *outbuffer);
+/**
+ * Translate IMM Value Type to string
+ *
+ * @param attrValueType[in]
+ *
+ * @return char*
+ */
+char* dbg_get_attr_type_name(SaImmValueTypeT attrValueType);
+
+/**
+ * Trace an array of IMM Attribute Modification
+ *
+ * @param **attrMods[in]
+ */
+void dbg_trace_attr_mods(const SaImmAttrModificationT_2 **attrMods);
+
+
+/**
+ * Trace an array of IMM Attribute Values
+ *
+ * @param **attrs[in]
+ */
+void dbg_trace_attrs(const SaImmAttrValuesT_2 **attrs);
+
+/**
+ * Trace one IMM Attribute Value
+ *
+ * @param **attr[in]
+ */
+void dbg_trace_attr(const SaImmAttrValuesT_2 *attr);
+
+/**
+ * For a given array of IMM Attribute Modifications, fetch the
+ * corresponding current IMM Attribute Values. The return data
+ * curAttr is managed by IMM unless a copy is requested.
+ * Deep clone method is used to copy the returned IMM Attribute Values
+ *
+ * @param *objectName[in]
+ * @param **attrMods[in]
+ * @param ***curAttr[out]
+ * @param copy[in]
+ * @return SaAisErrorT
+ */
+SaAisErrorT get_current_attrs(const SaNameT *objectName,
+    const SaImmAttrModificationT_2 **attrMods, SaImmAttrValuesT_2 ***curAttr,
+    SaBoolT copy, SaBoolT verbose);
+
+/**
+ * Deep clone IMM Attribute Values
+ *
+ * @param **src[in]
+ */
+SaImmAttrValuesT_2** imm_attributes_cpy(const SaImmAttrValuesT_2 **src);
+
+/**
+ * Deallocate memory used for deep cloning IMM Attribute Values
+ *
+ * @param **attrs[in]
+ */
+void free_imm_attrs(SaImmAttrValuesT_2 **attrs);
+
+/**
+ * Wrapper of current IMM Attribute Values
+ */
+typedef struct ImcnUserData {
+  SaBoolT currAttrAvailable;  // Indicate if currAttr exists
+  SaAisErrorT errorCode;      // The error code when fetching currAttr fail
[M]: Do we really need errorCode? It seems only for trace/log purpose
+  SaImmAttrValuesT_2 **currAttr;
+} ImcnUserData_t;
+
+/**
+ * Deallocate memory used by the Wrapper of current IMM Attribute Values
+ */
+void free_imcnUserData(void *data);
+
+/**
+ * Allocate memory used by the Wrapper of current IMM Attribute Values
+ */
+ImcnUserData_t* create_imcnUserData();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // NTF_NTFIMCND_NTFIMCN_COMMON_H_
diff --git a/src/ntf/ntfimcnd/ntfimcn_imm.c b/src/ntf/ntfimcnd/ntfimcn_imm.c
index 3f2c1a873..56bdf37c6 100644
--- a/src/ntf/ntfimcnd/ntfimcn_imm.c
+++ b/src/ntf/ntfimcnd/ntfimcn_imm.c
@@ -40,7 +40,9 @@
#include "ntfimcn_main.h"
  #include "ntfimcn_notifier.h"
+#include "ntfimcn_common.h"
+extern const char* CcbUtilOperationType_Str[];
  /*
   * Global variables
   */
@@ -289,6 +291,12 @@ static void free_ccb_data(CcbUtilCcbData_t *ccb_data) {
                        osaf_extended_name_free(ccb_data->userData);
                        free(ccb_data->userData);
                }
+               // Free userData in CcbUtilOperationData
+               struct CcbUtilOperationData* oper_data =
+                               ccb_data->operationListHead;
+               for (; oper_data!= NULL; oper_data = oper_data->next) {
+                       free_imcnUserData(oper_data->userData);
+               }
                ccbutil_deleteCcbData(ccb_data);
        }
  }
@@ -565,6 +573,28 @@ saImmOiCcbObjectModifyCallback(SaImmOiHandleT immOiHandle, 
SaImmOiCcbIdT ccbId,
        SaNameT *invoker_name_ptr;
        invoker_name_ptr = ccbUtilCcbData->userData;
+ if (ccbId > 0) {
+               struct CcbUtilOperationData *ccbOperData;
+               ccbOperData = ccbUtilCcbData->operationListTail;
+               SaImmAttrValuesT_2 **curAttr;
+               ImcnUserData_t* usrData = create_imcnUserData();
+               // Get and deep clone the current attributes
+               rc = get_current_attrs(objectName, attrMods, &curAttr,
+                               SA_TRUE, SA_FALSE);
+               usrData->errorCode = rc;
[M]: One suggestion, we create ImcnUserData only if the rc == SA_AIS_OK, then the code may be a bit shorter, and we won't need to add currAttrAvailable
+               if (SA_AIS_OK == rc) {
+                       usrData->currAttrAvailable = SA_TRUE;
+                       usrData->currAttr = curAttr;
+               } else {
+                       usrData->currAttrAvailable = SA_FALSE;
+                       TRACE("Failed to get current attributes");
[M] It is failure code here, we can add errorcode in this TRACE("Failed to get current attributes"), so we can remove errorCode in the ImcnUserData_t
+               }
+               if (ccbOperData->userData != NULL) {
+                       LOG_NO("userData is overwritten");
[M] The userData in ccbOper is overwritten, it sounds like more a warning/error than just a notice log
+               }
+               ccbOperData->userData = usrData;
+       }
+
        if (ccbId == 0) {
                /* Attribute change object create */
                ccbUtilOperationData = ccbUtilCcbData->operationListHead;
@@ -625,6 +655,8 @@ static SaAisErrorT 
saImmOiCcbCompletedCallback(SaImmOiHandleT immOiHandle,
                                               SaImmOiCcbIdT ccbId)
  {
        /* Nothing to do here */
+       TRACE_ENTER();
+       TRACE_LEAVE();
        return SA_AIS_OK;
  }
@@ -671,6 +703,9 @@ static void saImmOiCcbApplyCallback(SaImmOiHandleT immOiHandle,
                        ccbLast = SA_TRUE;
                }
+ TRACE("operationType = <%s>",
+                 CcbUtilOperationType_Str[ccbUtilOperationData
+                                          ->operationType]);
                switch (ccbUtilOperationData->operationType) {
                case CCBUTIL_CREATE:
                        rdn_attr_name = get_rdn_attr_name(
@@ -718,6 +753,30 @@ static void saImmOiCcbApplyCallback(SaImmOiHandleT 
immOiHandle,
case CCBUTIL_MODIFY:
                        invoke_name_ptr = ccbUtilCcbData->userData;
+                       TRACE("CCBUTIL_MODIFY; New attributes");
+                       dbg_trace_attr_mods(
+                               ccbUtilOperationData->param.modify.attrMods);
+                       TRACE("CCBUTIL_MODIFY; OLD attributes");
[M] The following code is mainly for logging, if we don't need currAttrAvaiable, it can be a bit shorter. I think we can remove currAttrAvailable as well?
+                       if (ccbUtilOperationData->userData != NULL) {
+                               ImcnUserData_t* userData =
+                                       (ImcnUserData_t*)
+                                       ccbUtilOperationData->userData;
+                               if (userData->currAttrAvailable == SA_FALSE) {
+                                       TRACE("CCBUTIL_MODIFY; OLD attributes"
+                                               "not available; "
+                                               "error code <%d>",
+                                               userData->errorCode);
+                               } else {
+                                       // At the moment, only trace it out
+                                       dbg_trace_attrs(
+                                               (const SaImmAttrValuesT_2 **)
+                                               userData->currAttr);
+                               }
+
+                       } else {
+                               LOG_NO("CCBUTIL_MODIFY; OLD attributes "
+                                               "cannot be collected");
+                       }
/* send_object_modify_notification */
                        internal_rc = ntfimcn_send_object_modify_notification(
@@ -912,6 +971,11 @@ int ntfimcn_imm_init(ntfimcn_cb_t *cb)
        if (initializeImmOmHandle(&cb->immOmHandle) == false) {
                internal_rc = NTFIMCN_INTERNAL_ERROR;
        }
+       cb->immAccessorHandle = 0;
+       if (immutil_saImmOmAccessorInitialize(cb->immOmHandle,
+               &cb->immAccessorHandle) == false) {
+               internal_rc = NTFIMCN_INTERNAL_ERROR;
+       }
done:
        TRACE_LEAVE();
diff --git a/src/ntf/ntfimcnd/ntfimcn_main.h b/src/ntf/ntfimcnd/ntfimcn_main.h
index de6b67664..1e12bbc80 100644
--- a/src/ntf/ntfimcnd/ntfimcn_main.h
+++ b/src/ntf/ntfimcnd/ntfimcn_main.h
@@ -42,6 +42,8 @@ extern "C" {
  typedef struct {
    SaImmHandleT immOmHandle; /* Handle form IMM OM Initialize */
    SaImmOiHandleT immOiHandle; /* Handle from IMM OI initialize */
+  SaImmAccessorHandleT
+       immAccessorHandle;  /* Handle from IMM Accessor Interface */
    SaSelectionObjectT
        immSelectionObject;  /* Selection Object to wait for IMM events */
    SaNtfHandleT ntf_handle; /* Handle from NTF initialize */
diff --git a/src/ntf/ntfimcnd/ntfimcn_notifier.c 
b/src/ntf/ntfimcnd/ntfimcn_notifier.c
index af1b6da7b..36b9f4a5b 100644
--- a/src/ntf/ntfimcnd/ntfimcn_notifier.c
+++ b/src/ntf/ntfimcnd/ntfimcn_notifier.c
@@ -37,6 +37,8 @@
  #include "base/osaf_extended_name.h"
#include "ntfimcn_main.h"
+#include "ntfimcn_common.h"
+
/* Release code, major version, minor version */
  const SaVersionT kNtfVersion = {'A', 0x01, 0x01};
@@ -44,6 +46,25 @@ const unsigned int sleep_delay_ms = 500;
  const unsigned int max_waiting_time_ms = 7 * 1000;       /* 7 secs */
  const unsigned int max_init_waiting_time_ms = 60 * 1000; /* 60 secs */
+extern const int DBG_MX_LEN;
+
+static const int NTFIMCN_NOT_FOUND = -1;
+static int find_attr_from_name(SaImmAttrValuesT_2** attrs, SaImmAttrNameT name)
+{
+       int pos = NTFIMCN_NOT_FOUND;
+       if (!attrs)
+               return pos;
+
+       SaImmAttrValuesT_2* attr = NULL;
+       for (int i = 0; (attr = attrs[i]) != NULL; ++i) {
+               if (strcmp(attr->attrName, name) == 0) {
+                       pos = i;
+                       break;
+               }
+       }
+       return pos;
+}
+
  /*
   * Global variables
   */
@@ -245,6 +266,119 @@ done:
        return internal_rc;
  }
+/**
+ * Fill in the old attribute value.
+ * Refer to fill_attribute_value() for detailed description of parameters.
+ * For each new attribute filled in by fill_attribute_value(),
+ * if the old attribute value exist, it will be filled in by this
+ * function.
+ * The old attribute value has the same attribute type and attribute Id
+ * as the new attribute.
+ *
+ * @param notificationHandle[in]
+ * @param attrValueType_in[in]
+ * @param *attrValues_in[in]
+ * @param attrValues_index_in[in]
+ * @param *value_out[out]
+ *
+ * @return (-1) on error
+ */
+static int fill_old_attribute_value(
+           SaNtfNotificationHandleT notificationHandle,
+           SaImmValueTypeT attrValueType_in,
+           SaImmAttrValueT *attrValues_in,
+           SaUint32T attrValues_index_in,
+           SaNtfValueT *value_out)
+{
+       int internal_rc = 0;
+       SaSizeT str_len = 0;
+       SaAnyT any_value;
+       SaNameT name_value;
+
+       TRACE_ENTER();
+
+       /* Insert value dependent on type.
+        * For possible types see SaImmValueTypeT */
+       switch (attrValueType_in) {
+       case SA_IMM_ATTR_SAINT32T:
+               value_out->int32Val =
+                   *((SaInt32T *)attrValues_in[attrValues_index_in]);
+               break;
+       case SA_IMM_ATTR_SAUINT32T:
+               value_out->uint32Val =
+                   *((SaUint32T *)attrValues_in[attrValues_index_in]);
+               break;
+       case SA_IMM_ATTR_SATIMET: /* SaTimeT (SaInt64T) */
+       case SA_IMM_ATTR_SAINT64T:
+               value_out->int64Val =
+                   *((SaInt64T *)attrValues_in[attrValues_index_in]);
+               break;
+       case SA_IMM_ATTR_SAUINT64T:
+               value_out->uint64Val =
+                   *((SaUint64T *)attrValues_in[attrValues_index_in]);
+               break;
+       case SA_IMM_ATTR_SAFLOATT:
+               value_out->floatVal =
+                   *((SaFloatT *)attrValues_in[attrValues_index_in]);
+               break;
+       case SA_IMM_ATTR_SADOUBLET:
+               value_out->doubleVal =
+                   *((SaDoubleT *)attrValues_in[attrValues_index_in]);
+               break;
+
+       case SA_IMM_ATTR_SANAMET: /* SaNameT */
+               name_value = *(SaNameT *)attrValues_in[attrValues_index_in];
+               str_len = strlen(osaf_extended_name_borrow(&name_value));
+               if (str_len == 0) ++str_len;
+               internal_rc = fill_value_array(
+                   notificationHandle,
+                   (SaUint8T *)osaf_extended_name_borrow(&name_value),
+                   str_len, value_out);
+               if (internal_rc != 0) {
+                       LOG_ER("%s: fill_value_array failed", __FUNCTION__);
+                       goto done;
+               }
+               break;
+
+       case SA_IMM_ATTR_SASTRINGT:
+               str_len =
+                   strlen(*(SaStringT *)attrValues_in[attrValues_index_in]) +
+                   1;
+
+               internal_rc = fill_value_array(
+                   notificationHandle,
+                   *(SaUint8T **)attrValues_in[attrValues_index_in], str_len,
+                   value_out);
+               if (internal_rc != 0) {
+                       LOG_ER("%s: fill_value_array failed", __FUNCTION__);
+                       goto done;
+               }
+               break;
+
+       case SA_IMM_ATTR_SAANYT: /* SaAnyT, SA_NTF_VALUE_BINARY */
+               any_value = *(SaAnyT *)attrValues_in[attrValues_index_in];
+               internal_rc = fill_value_array(notificationHandle,
+                                              (SaUint8T *)any_value.bufferAddr,
+                                              any_value.bufferSize, value_out);
+               if (internal_rc != 0) {
+                       LOG_ER("%s: fill_value_array failed", __FUNCTION__);
+                       goto done;
+               }
+               break;
+
+       default:
+               LOG_ER("%s Invalid attributeType %d", __FUNCTION__,
+                      attrValueType_in);
+               internal_rc = (-1);
+               break;
+       }
+
+done:
+       TRACE_LEAVE();
+       return internal_rc;
+}
+
+
  /**
   * Fill in the attribute value and type. The value can be of
   * different types and may also be a multi-value which is an array of values
@@ -747,7 +881,8 @@ done:
   */
  static int fill_attribute_info_modify(
      SaImmOiCcbIdT CcbId, SaConstStringT invoke_name,
-    const SaImmAttrModificationT_2 **imm_attr_mods_in,
+    const SaImmAttrModificationT_2 **imm_attr_mods_in, // New attributes
+    const ImcnUserData_t* userData,           // Old attributes if exist
      SaNtfAttributeChangeNotificationT *SaNtfAttributeChangeNotification,
      SaBoolT ccbLast)
  {
@@ -763,6 +898,16 @@ static int fill_attribute_info_modify(
TRACE_ENTER(); + SaImmAttrValuesT_2** old_imm_attr_values = NULL;
+       SaImmAttrValuesT_2* old_imm_attr_value = NULL;
+       // Get the old attribute values if present
+       int pos = NTFIMCN_NOT_FOUND;
+       if (userData) {
+               if (userData->currAttrAvailable == SA_TRUE) {
+                       old_imm_attr_values = userData->currAttr;
+               }
+       }
+
        my_imm_attr_mod.modAttr.attrValues = &SaImmAttrValue;
[M] The saImmAttrValue it seems not used?
        imm_attr_mods = imm_attr_mods_in[imm_index++];
@@ -792,6 +937,7 @@ static int fill_attribute_info_modify(
                        }
/* Fill Corresponding Attribute Value */
+                       /* The old value exists in IMM but not populated */
                        changedAttributes = &SaNtfAttributeChangeNotification
                                                 ->changedAttributes[1];
                        changedAttributes->oldAttributePresent = SA_FALSE;
@@ -810,7 +956,6 @@ static int fill_attribute_info_modify(
                                       __FUNCTION__);
                                goto done;
                        }
-
                } else if (strcmp(imm_attr_mods->modAttr.attrName,
                                  NTFIMCN_IMPLEMENTER_NAME) == 0) {
                        /* Do not handle here since it is handled separately.
@@ -834,6 +979,20 @@ static int fill_attribute_info_modify(
                                goto done;
                        }
+ // Get old attribute values corresponding to the
+                       // new attributes below. Can be multi value or
+                       // no value
+                       pos = find_attr_from_name(old_imm_attr_values,
+                           imm_attr_mods->modAttr.attrName);
+                       char buff[DBG_MX_LEN];
+                       char* pbuff = buff;
+                       if (pos != NTFIMCN_NOT_FOUND) {
+                               old_imm_attr_value = old_imm_attr_values[pos];
+                       } else {
+                               old_imm_attr_value = NULL;
+                       }
+                       TRACE("old_imm_attr_value is <%s>",
+                                       old_imm_attr_value? "not null": "null");
                        /* Fill Corresponding Attribute Value
                         * Can be a multi value or no value.
                         */
@@ -863,6 +1022,39 @@ static int fill_attribute_info_modify(
                                            __FUNCTION__);
                                        goto done;
                                }
+                               // There can be more new attribute values than
+                               // old attribute values,at least one
+                               dbg_format_attr_value(
+                                  imm_attr_mods->modAttr.attrValueType,
+                                  imm_attr_mods->modAttr.attrValues[vindex],
+                                  pbuff);
+                               TRACE("New IMM value <%s>", pbuff);
+                               if (old_imm_attr_value &&
+                                  (vindex < old_imm_attr_value
+                                   ->attrValuesNumber)) {
+                                       changedAttributes->oldAttributePresent =
+                                          SA_TRUE;
+                                       internal_rc = fill_old_attribute_value(
[M] Can we generalize the fill_old_attribute_value and fill_attribute_value to be one function? So we don't have two functions that are pretty much doing a similar functionality, which is fill IMM value to a NtfValueT
+                                          SaNtfAttributeChangeNotification
+                                          ->notificationHandle,
+                                          old_imm_attr_value->attrValueType,
+                                          old_imm_attr_value->attrValues,
+                                          vindex,  /* Index of attrValues in */
+                                          &changedAttributes
+                                          ->oldAttributeValue);
+                                       if (internal_rc != 0) {
+                                          LOG_ER(
+                                          "%s: fill_attribute_value failed",
+                                          __FUNCTION__);
+                                               goto done;
+                                       }
+                                       dbg_format_attr_value(
+                                          imm_attr_mods->modAttr.attrValueType,
+                                          old_imm_attr_value
+                                          ->attrValues[vindex],
+                                          pbuff);
+                                       TRACE("Old IMM value <%s>", pbuff);
+                               }
                        }
var_index += vindex;
@@ -900,6 +1092,7 @@ static int fill_attribute_info_modify(
        }
/* Fill Corresponding Attribute Value */
+       /* The old value exists in IMM but not populated */
        changedAttributes =
            &SaNtfAttributeChangeNotification->changedAttributes[0];
        changedAttributes->oldAttributePresent = SA_FALSE;
@@ -937,7 +1130,6 @@ static int fill_attribute_info_modify(
                /* Fill Corresponding Attribute Value */
                changedAttributes =
                    &SaNtfAttributeChangeNotification->changedAttributes[2];
-               changedAttributes->oldAttributePresent = SA_FALSE;
                internal_rc = fill_attribute_value(
                    SaNtfAttributeChangeNotification->notificationHandle,
                    my_imm_attr_mod.modAttr.attrValueType,
@@ -951,6 +1143,23 @@ static int fill_attribute_info_modify(
                        LOG_ER("%s: fill_attribute_value failed", __FUNCTION__);
                        goto done;
                }
+               if (old_imm_attr_values) {
+                       changedAttributes->oldAttributePresent = SA_TRUE;
+                       internal_rc = fill_old_attribute_value(
+                          SaNtfAttributeChangeNotification
+                          ->notificationHandle,
+                          my_imm_attr_mod.modAttr.attrValueType,
+                          my_imm_attr_mod.modAttr.attrValues,
+                          0,    /* Index of attrValues in */
+                          &changedAttributes->oldAttributeValue);
+                       if (internal_rc != 0) {
+                          LOG_ER("%s: fill_attribute_value failed",
+                          __FUNCTION__);
+                          goto done;
+                       }
+               } else {
+                       changedAttributes->oldAttributePresent = SA_FALSE;
+               }
        }
/* Id 3: ccbLast
@@ -975,7 +1184,6 @@ static int fill_attribute_info_modify(
                /* Fill Corresponding Attribute Value */a
                changedAttributes =
                    &SaNtfAttributeChangeNotification->changedAttributes[3];
-               changedAttributes->oldAttributePresent = SA_FALSE;
                internal_rc = fill_attribute_value(
                    SaNtfAttributeChangeNotification->notificationHandle,
                    my_imm_attr_mod.modAttr.attrValueType,
@@ -989,6 +1197,23 @@ static int fill_attribute_info_modify(
                        LOG_ER("%s: fill_attribute_value failed", __FUNCTION__);
                        goto done;
                }
+               if (old_imm_attr_values) {
+                       changedAttributes->oldAttributePresent = SA_TRUE;
+                       internal_rc = fill_old_attribute_value(
+                           SaNtfAttributeChangeNotification
+                           ->notificationHandle,
+                           my_imm_attr_mod.modAttr.attrValueType,
+                           my_imm_attr_mod.modAttr.attrValues,
+                           0,    /* Index of attrValues in */
+                           &changedAttributes->oldAttributeValue);
+                       if (internal_rc != 0) {
+                               LOG_ER("%s: fill_attribute_value failed",
+                                  __FUNCTION__);
+                               goto done;
+                       }
+               } else {
+                       changedAttributes->oldAttributePresent = SA_FALSE;
+               }
        }
done:
@@ -1391,6 +1616,7 @@ int ntfimcn_send_object_modify_notification(
         */
        internal_rc = fill_attribute_info_modify(
            CcbId, invoke_name_str, CcbUtilOperationData->param.modify.attrMods,
+           (ImcnUserData_t*) CcbUtilOperationData->userData,
            &SaNtfAttributeChangeNotification, ccbLast);
        if (internal_rc != 0) {
                LOG_ER("%s: ntfimcn_fill_attribute_info failed", __FUNCTION__);

_______________________________________________
Opensaf-devel mailing list
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to