SMF imm operation lists may contain duplicate create operations.
Fix, rollback data shall not be stored for duplicate operations and
duplicate operations shall not be added to the CCB.
Fix, crash in SmfUtil::doImmoperation if the CCB fails
---
 opensaf.spec.in                               |   3 +-
 src/smf/Makefile.am                           |  42 ++-
 src/smf/smfd/SmfUtils.cc                      |  72 ++++-
 src/smf/smfd/SmfUtils_ObjExist.cc             | 290 ++++++++++++++++++
 src/smf/smfd/SmfUtils_ObjExist.h              |  68 ++++
 .../imm_modify_config/add_operation_to_ccb.cc |   5 +-
 src/smf/smfd/imm_modify_config/immccb.h       |  53 +++-
 .../{ccbhdl_test.cc => test_ccbhdl.cc}        |   0
 src/smf/smfd/imm_modify_demo/test_objexist.cc | 127 ++++++++
 9 files changed, 633 insertions(+), 27 deletions(-)
 create mode 100644 src/smf/smfd/SmfUtils_ObjExist.cc
 create mode 100644 src/smf/smfd/SmfUtils_ObjExist.h
 rename src/smf/smfd/imm_modify_demo/{ccbhdl_test.cc => test_ccbhdl.cc} (100%)
 create mode 100644 src/smf/smfd/imm_modify_demo/test_objexist.cc

diff --git a/opensaf.spec.in b/opensaf.spec.in
index 3d7ac28a9..5ae2070d4 100644
--- a/opensaf.spec.in
+++ b/opensaf.spec.in
@@ -1538,7 +1538,8 @@ fi
 %{_bindir}/ccbdemo_create
 %{_bindir}/ccbdemo_delete
 %{_bindir}/ccbdemo_modify
-%{_bindir}/ccbhdl_test
+%{_bindir}/test_ccbhdl
+%{_bindir}/test_objexist
 %endif
 %if %is_ais_ckpt
 %{_bindir}/ckpttest
diff --git a/src/smf/Makefile.am b/src/smf/Makefile.am
index 3502f1546..5eed2e683 100644
--- a/src/smf/Makefile.am
+++ b/src/smf/Makefile.am
@@ -106,6 +106,7 @@ noinst_HEADERS += \
        src/smf/smfd/SmfUpgradeProcedure.h \
        src/smf/smfd/SmfUpgradeStep.h \
        src/smf/smfd/SmfUtils.h \
+       src/smf/smfd/SmfUtils_ObjExist.h \
        src/smf/smfd/smfd.h \
        src/smf/smfd/smfd_cb.h \
        src/smf/smfd/smfd_evt.h \
@@ -198,6 +199,7 @@ bin_osafsmfd_SOURCES = \
        src/smf/smfd/SmfUpgradeProcedure.cc \
        src/smf/smfd/SmfUpgradeStep.cc \
        src/smf/smfd/SmfUtils.cc \
+       src/smf/smfd/SmfUtils_ObjExist.cc \
        src/smf/smfd/smfd_amf.cc \
        src/smf/smfd/smfd_campaign_oi.cc \
        src/smf/smfd/smfd_evt.c \
@@ -261,7 +263,12 @@ endif
 # Demos and test
 if ENABLE_TESTS
 
-bin_PROGRAMS += bin/ccbdemo_create bin/ccbdemo_delete bin/ccbdemo_modify 
bin/ccbhdl_test
+bin_PROGRAMS += \
+       bin/ccbdemo_create \
+       bin/ccbdemo_delete \
+       bin/ccbdemo_modify \
+       bin/test_ccbhdl \
+       bin/test_objexist
 
 dist_pkgimmxml_svc_DATA += \
        src/smf/smfd/imm_modify_demo/democlass.xml
@@ -377,26 +384,26 @@ bin_ccbdemo_modify_LDADD = \
        lib/libSaImmOm.la \
        lib/libopensaf_core.la
 
-# CCBHDL Test
+# Test CCBHDL
 # -----------
-bin_ccbhdl_test_CFLAGS = $(AM_CFLAGS) -Wformat=1
+bin_test_ccbhdl_CFLAGS = $(AM_CFLAGS) -Wformat=1
 
-bin_ccbhdl_test_CPPFLAGS = \
+bin_test_ccbhdl_CPPFLAGS = \
        -DSA_EXTENDED_NAME_SOURCE \
        $(AM_CPPFLAGS)
 
-bin_ccbhdl_test_SOURCES = \
+bin_test_ccbhdl_SOURCES = \
        src/smf/smfd/imm_modify_demo/common.cc \
-       src/smf/smfd/imm_modify_demo/ccbhdl_test.cc
+       src/smf/smfd/imm_modify_demo/test_ccbhdl.cc
 
 # IMM configuration modifier
-bin_ccbhdl_test_SOURCES += \
+bin_test_ccbhdl_SOURCES += \
        src/smf/smfd/imm_modify_config/attribute.cc \
        src/smf/smfd/imm_modify_config/add_operation_to_ccb.cc \
        src/smf/smfd/imm_modify_config/immccb.cc
 
 # IMM OM C++ APIs
-bin_ccbhdl_test_SOURCES += \
+bin_test_ccbhdl_SOURCES += \
        src/smf/smfd/imm_om_ccapi/common/common.cc \
        src/smf/smfd/imm_om_ccapi/common/imm_attribute.cc \
        src/smf/smfd/imm_om_ccapi/om_admin_owner_clear.cc \
@@ -408,7 +415,24 @@ bin_ccbhdl_test_SOURCES += \
        src/smf/smfd/imm_om_ccapi/om_ccb_object_modify.cc \
        src/smf/smfd/imm_om_ccapi/om_handle.cc
 
-bin_ccbhdl_test_LDADD = \
+bin_test_ccbhdl_LDADD = \
+       lib/libosaf_common.la \
+       lib/libSaImmOm.la \
+       lib/libopensaf_core.la
+
+# Test OBJEXIST
+# -------------
+bin_test_objexist_CFLAGS = $(AM_CFLAGS) -Wformat=1
+
+bin_test_objexist_CPPFLAGS = \
+       -DSA_EXTENDED_NAME_SOURCE \
+       $(AM_CPPFLAGS)
+
+bin_test_objexist_SOURCES = \
+       src/smf/smfd/SmfUtils_ObjExist.cc \
+       src/smf/smfd/imm_modify_demo/test_objexist.cc
+
+bin_test_objexist_LDADD = \
        lib/libosaf_common.la \
        lib/libSaImmOm.la \
        lib/libopensaf_core.la
diff --git a/src/smf/smfd/SmfUtils.cc b/src/smf/smfd/SmfUtils.cc
index 8815faa63..020392ada 100644
--- a/src/smf/smfd/SmfUtils.cc
+++ b/src/smf/smfd/SmfUtils.cc
@@ -30,9 +30,11 @@
 #include "ais/include/saAis.h"
 #include "ais/include/saAmf.h"
 #include "ais/include/saSmf.h"
+#include "ais/include/saImmOm.h"
 #include "base/saf_error.h"
 #include "base/osaf_extended_name.h"
 #include "base/osaf_time.h"
+#include "base/time.h"
 
 #include "osaf/immutil/immutil.h"
 
@@ -41,6 +43,7 @@
 #include "smf/smfd/smfd_smfnd.h"
 #include "smf/smfd/SmfImmOperation.h"
 #include "smf/smfd/SmfRollback.h"
+#include "SmfUtils_ObjExist.h"
 
 /* ========================================================================
  *   DEFINITIONS
@@ -640,8 +643,17 @@ done:
 // -----------------
 // doImmOperations()
 // -----------------
-
-// Help function for doImmOperations
+// Note: This method will use two IMM Om. The timeout time for each is set to
+// two minutes. This may seem as we may have to wait for up to 4 minutes or
+// longer in some situations but this is not the case.
+// The only reason for a long wait is when creating an OM handle when IMM
+// synchronization is going on. Once the synchronization is done the rest of
+// the OM handling is going fast. However, we don't know when a synchronization
+// is started so a long timeout is needed in all places where an OM handle is
+// requested.
+
+// Help functions for doImmOperations
+// ----------------------------------
 // Check if the class name begin with "SaAmf" and ends with "Type"
 static bool IsAmfTypeClass(const modelmodify::CreateDescriptor&
                             object_to_check) {
@@ -669,6 +681,10 @@ SaAisErrorT SmfImmUtils::doImmOperations(
   modelmodify::ModelModification modifier;
   // Note: ccb flags are default set to 0 (do not require OI)
 
+  // Note: This object should be created once
+  CheckObjectExist object_exist_check;
+  CheckObjectExist::ReturnCode obj_exist_rc = 
CheckObjectExist::ReturnCode::kOk;
+
   for (auto& imm_operation : i_immOperationList) {
     // Create rollback object for each operation in CCB there if requested
     SmfRollbackData *rollbackData = NULL;
@@ -696,15 +712,53 @@ SaAisErrorT SmfImmUtils::doImmOperations(
       // If the name of the object starts with "SaAmf" and ends with "Type"
       // then ignore if the object already exist
       // (set ignore_ais_err_exist = true in imm_modifications)
-      // Note: Is done here since the connection between SmfImmOperation and
+      // Note1: Is done here since the connection between SmfImmOperation and
       // this util function is not strong enough (can be used separately) also
-      // the criteria for ignoring exist is defined here
+      // the criteria for ignoring exist is defined here.
+      // Note2: We must still check if the object actually exist here since the
+      // rollback data that is always created must be deleted if the create
+      // is not done. Otherwise rollback will fail. The way of doing this is
+      // to use an IMM access operation. Handling the CCB is done as a
+      // transaction and it is not possible to see in this loop if an object
+      // creation will be ignored or not.
+      //
+
+      TRACE("%s: Create operation", __FUNCTION__);
+
       modelmodify::CreateDescriptor create_descriptor =
           imm_operation->GetCreateDescriptor();
+
+      // If the object to be created already exists:
+      // - Do not add the create descriptor to the CCB descriptor
+      // - Delete the rollbackData that was created by
+      //   imm_operation->Execute(rollbackData)
       if (IsAmfTypeClass(create_descriptor)) {
-        create_descriptor.ignore_ais_err_exist = true;
+        TRACE("%s: IsAmfTypeClass() true, class = %s", __FUNCTION__,
+              create_descriptor.class_name.c_str());
+
+        obj_exist_rc = object_exist_check.IsExisting(create_descriptor);
+        if (obj_exist_rc == CheckObjectExist::ReturnCode::kOk) {
+          // The object in the create descriptor already exist in the IMM model
+          // The create descriptor shall not be added to the ccb descriptor and
+          // any corresponding rollback data shall be deleted
+          TRACE("%s Object already in IMM model", __FUNCTION__);
+          if (rollbackData != NULL) {
+            delete rollbackData;
+            rollbackData = NULL;
+          }
+        } else if (imm_modifications.AddCreate(create_descriptor) == false) {
+          // The create descriptor is a duplicate and is not added to the CCB
+          // Any corresponding rollbackData shall be deleted
+          TRACE("%s Duplicate Create operation found", __FUNCTION__);
+          if (rollbackData != NULL) {
+            delete rollbackData;
+            rollbackData = NULL;
+          }
+        }
+      } else {
+        // Is not an Amf type class so always add the create descriptor
+        imm_modifications.AddCreate(create_descriptor);
       }
-      imm_modifications.AddCreate(create_descriptor);
     } else if (imm_operation->GetOperationType() == SmfImmOperation::Delete) {
       // Never Fail if an object to delete does not exist
       imm_modifications.AddDelete(imm_operation->GetDeleteDescriptor());
@@ -733,11 +787,13 @@ SaAisErrorT SmfImmUtils::doImmOperations(
         // Operation failed for other reason than AIS error return from IMM
         result = SA_AIS_ERR_FAILED_OPERATION;
       }
+      LOG_NO("%s: DoModelModification() Fail, %s in '%s'", __FUNCTION__,
+             saf_error(result), error_info.api_name.c_str());
     }
   }
 
-  if (result != SA_AIS_OK) {
-    // Clear the rollback ccb list if we fail
+  if ((result != SA_AIS_OK) && (io_rollbackCcb != NULL)) {
+    // Clear the rollback ccb list if we fail (if there is a list)
     io_rollbackCcb->clearCcbData();
   }
 
diff --git a/src/smf/smfd/SmfUtils_ObjExist.cc 
b/src/smf/smfd/SmfUtils_ObjExist.cc
new file mode 100644
index 000000000..7eaba6c3a
--- /dev/null
+++ b/src/smf/smfd/SmfUtils_ObjExist.cc
@@ -0,0 +1,290 @@
+/*      -*- OpenSAF  -*-
+ *
+ * Copyright Ericsson AB 2018 - All Rights Reserved.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
+ * under the GNU Lesser General Public License Version 2.1, February 1999.
+ * The complete license can be accessed from the following location:
+ * http://opensource.org/licenses/lgpl-license.php
+ * See the Copying file included with the OpenSAF distribution for full
+ * licensing terms.
+ *
+ * Author(s): Ericsson AB
+ *
+ */
+
+#include "smf/smfd/SmfUtils_ObjExist.h"
+
+#include <string.h>
+#include <iostream>
+
+#include "ais/include/saAis.h"
+#include "ais/include/saImmOm.h"
+#include "base/saf_error.h"
+#include "base/osaf_extended_name.h"
+#include "base/time.h"
+
+#include "smf/smfd/imm_modify_config/immccb.h"
+
+  // Check if the object exist. If fail use recovery possibilities
+  // The Object DN is created from class and parent name
+  CheckObjectExist::ReturnCode CheckObjectExist::IsExisting(
+                          modelmodify::CreateDescriptor& create_descriptor) {
+    // Allow for two max time retries
+    base::Timer check_timer(120000);  // 2 minutes
+    ReturnCode rc = ReturnCode::kOk;
+
+    while (check_timer.is_timeout() != true) {
+      if (is_initialized_ != true) {
+        // Only initialize if not already initialized
+        if (OmInitialize() != ReturnCode::kOk) {
+          LOG_NO("%s: OmInitialize(), Fail", __FUNCTION__);
+          rc = ReturnCode::kFail;
+          break;
+        }
+
+        ReturnCode acci_rc = AccesorInitialize();
+        if (acci_rc == ReturnCode::kRestartOm) {
+          // No delay needed here
+          continue;
+        } else if (acci_rc == kFail) {
+          LOG_NO("%s: AccesorInitialize(), Fail", __FUNCTION__);
+          rc = ReturnCode::kFail;
+          break;
+        }
+      }
+
+      ReturnCode getrdn_rc = GetObjectRdn(create_descriptor);
+      if (getrdn_rc == ReturnCode::kRestartOm) {
+        is_initialized_ = false;
+        // No delay needed here
+        continue;
+      } else if (getrdn_rc == kFail) {
+        LOG_NO("%s: GetObjectRdn(), Fail", __FUNCTION__);
+        is_initialized_ = false;
+        rc = ReturnCode::kFail;
+        break;
+      }
+
+      std::string object_dn = object_rdn_;
+      if (create_descriptor.parent_name.empty() == false) {
+        object_dn += "," + create_descriptor.parent_name;
+      }
+
+      ReturnCode aget_rc = AccessorGet(object_dn);
+      if (aget_rc == ReturnCode::kRestartOm) {
+        is_initialized_ = false;
+        // No delay needed here
+        continue;
+      }
+      if (aget_rc == ReturnCode::kFail) {
+        LOG_NO("%s: AccessorGet(), Fail", __FUNCTION__);
+        is_initialized_ = false;
+        rc = ReturnCode::kFail;
+        break;
+      }
+
+      // If we get here we did not fail and have a valid result
+      rc = aget_rc;
+      break;
+    }  // check_timer.is_timeout()
+    if ((check_timer.is_timeout() == true) && (rc != ReturnCode::kOk)) {
+      LOG_NO("%s: IsExisting Timeout", __FUNCTION__);
+      is_initialized_ = false;
+      rc = ReturnCode::kFail;
+    }
+
+    if (rc == ReturnCode::kOk) {
+      is_initialized_ = true;
+    }
+    return rc;
+  }
+
+
+  // Update om_handle_
+  CheckObjectExist::ReturnCode CheckObjectExist::OmInitialize() {
+    // Long timeout. We may have to wait for IMM sync
+    base::Timer init_timer(60000);  // 1 minute
+    SaAisErrorT ais_rc = SA_AIS_OK;
+    ReturnCode rc = ReturnCode::kOk;
+
+    if (om_handle_ != 0) {
+      saImmOmFinalize(om_handle_);
+      om_handle_ = 0;
+    }
+
+    while (init_timer.is_timeout() != true) {
+      SaVersionT tmp_version = kImmVersion;
+      ais_rc = saImmOmInitialize(&om_handle_, NULL, &tmp_version);
+      if (ais_rc == SA_AIS_ERR_TRY_AGAIN) {
+        base::Sleep(base::kOneHundredMilliseconds);
+        continue;
+      } else if (ais_rc != SA_AIS_OK) {
+        rc = ReturnCode::kFail;
+        LOG_NO("%s: saImmOmInitialize Fail, %s", __FUNCTION__,
+               saf_error(ais_rc));
+        break;
+      }
+      rc = ReturnCode::kOk;
+      break;
+    }
+    if (init_timer.is_timeout() && ais_rc != SA_AIS_OK) {
+      LOG_NO("%s: saImmOmInitialize Timeout, %s", __FUNCTION__,
+             saf_error(ais_rc));
+      rc = ReturnCode::kFail;
+    }
+
+    return rc;
+  }
+
+  // Update accessor_handle_
+  CheckObjectExist::ReturnCode CheckObjectExist::AccesorInitialize() {
+    base::Timer init_timer(10000);  // 10 seconds
+    SaAisErrorT ais_rc = SA_AIS_OK;
+    ReturnCode rc = ReturnCode::kOk;
+
+    while (init_timer.is_timeout() != true) {
+      ais_rc = saImmOmAccessorInitialize(om_handle_, &accessor_handle_);
+      if (ais_rc == SA_AIS_ERR_TRY_AGAIN) {
+        base::Sleep(base::kOneHundredMilliseconds);
+        continue;
+      } else if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
+        rc = ReturnCode::kRestartOm;
+        break;
+      } else if (ais_rc != SA_AIS_OK) {
+        LOG_NO("%s: saImmOmAccessorInitialize Fail, %s", __FUNCTION__,
+               saf_error(ais_rc));
+        rc = ReturnCode::kFail;
+        break;
+      }
+      rc = ReturnCode::kOk;
+      break;
+    }
+    if (init_timer.is_timeout() && ais_rc != SA_AIS_OK) {
+      LOG_NO("%s: saImmOmAccessorInitialize Timeout, %s", __FUNCTION__,
+             saf_error(ais_rc));
+      rc = ReturnCode::kFail;
+    }
+
+    return rc;
+  }
+
+  // Check object existence
+  CheckObjectExist::ReturnCode CheckObjectExist::AccessorGet(std::string
+                                                             object_dn) {
+    ReturnCode rc = ReturnCode::kOk;
+    SaAisErrorT ais_rc = SA_AIS_OK;
+    SaImmAttrValuesT_2 **fetched_attributes;  // Dummy, not used
+    SaNameT object_dn_as_sanamet;
+    osaf_extended_name_lend(object_dn.c_str(), &object_dn_as_sanamet);
+
+    base::Timer get_timer(10000);  // 10 seconds
+    while (get_timer.is_timeout() == false) {
+      ais_rc = saImmOmAccessorGet_2(accessor_handle_,
+                                    &object_dn_as_sanamet,
+                                    NULL,
+                                    &fetched_attributes);
+      if (ais_rc == SA_AIS_ERR_TRY_AGAIN) {
+        base::Sleep(base::kOneHundredMilliseconds);
+        continue;
+      }
+      if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
+        rc = ReturnCode::kRestartOm;
+        break;
+      }
+      if (ais_rc == SA_AIS_ERR_NOT_EXIST) {
+        rc = ReturnCode::kNotExist;
+        break;
+      }
+      if (ais_rc == SA_AIS_OK) {
+        rc = ReturnCode::kOk;
+        break;
+      }
+
+      // All other ais error codes is a fail
+      LOG_NO("%s: saImmOmAccessorGet_2 Fail, %s", __FUNCTION__,
+             saf_error(ais_rc));
+      rc = ReturnCode::kFail;
+      break;
+    }
+    if (get_timer.is_timeout() &&
+        (ais_rc != SA_AIS_OK) &&
+        (ais_rc != SA_AIS_ERR_NOT_EXIST)) {
+      // Timeout fail only if we failed to get a result
+      LOG_NO("%s: saImmOmAccessorGet_2 Timeout, %s", __FUNCTION__,
+             saf_error(ais_rc));
+      rc = ReturnCode::kFail;
+    }
+
+    return rc;
+  }
+
+  // Update object_rdn_
+  CheckObjectExist::ReturnCode CheckObjectExist::GetObjectRdn(
+                          modelmodify::CreateDescriptor& create_descriptor ) {
+    SaAisErrorT ais_rc = SA_AIS_OK;
+    ReturnCode rc = ReturnCode::kOk;
+
+    // Get the class descriptor
+    SaImmAttrDefinitionT_2** attr_definitions;
+    SaImmClassCategoryT class_category = SA_IMM_CLASS_CONFIG;
+    SaImmClassNameT class_name = const_cast<char *>
+                                 (create_descriptor.class_name.c_str());
+
+    base::Timer get_timer(10000);  // 10 seconds
+    while (get_timer.is_timeout() == false) {
+      ais_rc = saImmOmClassDescriptionGet_2(om_handle_,
+                                            class_name,
+                                            &class_category,
+                                            &attr_definitions);
+      if (ais_rc == SA_AIS_ERR_TRY_AGAIN) {
+        base::Sleep(base::kOneHundredMilliseconds);
+        continue;
+      } else if (ais_rc == SA_AIS_ERR_BAD_HANDLE) {
+        rc = ReturnCode::kRestartOm;
+        break;
+      } else if (ais_rc != SA_AIS_OK) {
+        LOG_NO("%s: saImmOmClassDescriptionGet_2 Fail, %s", __FUNCTION__,
+               saf_error(ais_rc));
+        rc = ReturnCode::kFail;
+        break;
+      }
+      rc = ReturnCode::kOk;
+      break;
+    }
+    if (get_timer.is_timeout() && ais_rc != SA_AIS_OK) {
+      LOG_NO("%s: saImmOmClassDescriptionGet_2 Timeout, %s", __FUNCTION__,
+             saf_error(ais_rc));
+      rc = ReturnCode::kFail;
+    }
+
+    if (rc == ReturnCode::kOk) {
+      // Find name of RDN attribute
+      std::string rdn_attr;
+      for (int i = 0; attr_definitions[i] != nullptr; i++) {
+        SaImmAttrFlagsT flags = attr_definitions[i]->attrFlags;
+        if ((flags & SA_IMM_ATTR_RDN) == SA_IMM_ATTR_RDN) {
+          rdn_attr = reinterpret_cast<char *>(attr_definitions[i]->attrName);
+          break;
+        }
+      }
+
+      // Find attribute value of RDN attribute (object RDN)
+      for (auto& attribute : create_descriptor.attributes) {
+        if (attribute.attribute_name == rdn_attr) {
+          if (attribute.values_as_strings.empty()) {
+            object_rdn_ = "";
+          } else {
+            object_rdn_ = attribute.values_as_strings[0];
+          }
+          break;
+        }
+      }
+    } else {
+      object_rdn_ == "";
+    }
+
+    return rc;
+  }
diff --git a/src/smf/smfd/SmfUtils_ObjExist.h b/src/smf/smfd/SmfUtils_ObjExist.h
new file mode 100644
index 000000000..530970e00
--- /dev/null
+++ b/src/smf/smfd/SmfUtils_ObjExist.h
@@ -0,0 +1,68 @@
+/*      -*- OpenSAF  -*-
+ *
+ * Copyright Ericsson AB 2018 - All Rights Reserved.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
+ * under the GNU Lesser General Public License Version 2.1, February 1999.
+ * The complete license can be accessed from the following location:
+ * http://opensource.org/licenses/lgpl-license.php
+ * See the Copying file included with the OpenSAF distribution for full
+ * licensing terms.
+ *
+ * Author(s): Ericsson AB
+ *
+ */
+
+#ifndef SMFUTILS_OBJEXIST_H
+#define SMFUTILS_OBJEXIST_H
+
+#include <string>
+
+#include "ais/include/saAis.h"
+#include "ais/include/saImmOm.h"
+
+#include "smf/smfd/imm_modify_config/immccb.h"
+
+// Check if an IMM object exists.
+// Return: kOk if object exist, kNotExist if not exist and kFail if failing to
+//         get the information
+// Note1: An IMM access operation is used. An IMM access operation is fast and
+//        done locally on the node.
+// Note2: To make many checks (in a loop) more efficient the handles are
+//        created once.
+class CheckObjectExist {
+ public:
+  enum ReturnCode { kOk, kRestartOm, kFail, kNotExist };
+
+  CheckObjectExist()
+    : is_initialized_(false), om_handle_(0), accessor_handle_(0) {}
+  ~CheckObjectExist() { saImmOmFinalize(om_handle_); }
+
+  // Check if the object exist. If fail use recovery possibilities
+  // The Object DN is created from class and parent name
+  ReturnCode IsExisting(modelmodify::CreateDescriptor& create_descriptor);
+
+ private:
+  // Update om_handle_
+  ReturnCode OmInitialize();
+
+  // Update accessor_handle_
+  ReturnCode AccesorInitialize();
+
+  // Check object existence
+  ReturnCode AccessorGet(std::string object_dn);
+
+  // Update object_rdn_
+  ReturnCode GetObjectRdn(modelmodify::CreateDescriptor& create_descriptor );
+
+  std::string object_rdn_;
+  bool is_initialized_;
+  SaImmHandleT om_handle_;
+  SaImmAccessorHandleT accessor_handle_;
+  const SaVersionT kImmVersion = {'A', 2, 17};
+};
+
+#endif /* SMFUTILS_OBJEXIST_H */
+
diff --git a/src/smf/smfd/imm_modify_config/add_operation_to_ccb.cc 
b/src/smf/smfd/imm_modify_config/add_operation_to_ccb.cc
index 803556561..ad9209d4b 100644
--- a/src/smf/smfd/imm_modify_config/add_operation_to_ccb.cc
+++ b/src/smf/smfd/imm_modify_config/add_operation_to_ccb.cc
@@ -124,9 +124,10 @@ int AddCreateToCcb(const SaImmCcbHandleT& ccb_handle,
           recovery_info = kContinue;
         } else {
           recovery_info = kFail;
-          api_name_ = "saImmOmCcbObjectCreate_2";
-          ais_error_ = ais_rc;
         }
+        // Note: This information is always needed also if we do not fail
+        api_name_ = "saImmOmCcbObjectCreate_2";
+        ais_error_ = ais_rc;
       } else {
         // Unrecoverable Fail
         LOG_NO("%s: ObjectCreateCcbAdd(), %s, kFail",
diff --git a/src/smf/smfd/imm_modify_config/immccb.h 
b/src/smf/smfd/imm_modify_config/immccb.h
index 583ea59fd..9fd36765e 100644
--- a/src/smf/smfd/imm_modify_config/immccb.h
+++ b/src/smf/smfd/imm_modify_config/immccb.h
@@ -133,12 +133,24 @@ static inline SaImmAttrModificationTypeT 
StringToImmAttrModType(const
 struct AttributeDescriptor {
   std::string attribute_name;
   SaImmValueTypeT value_type;
+  std::vector<std::string> values_as_strings;
 
   void AddValue(std::string value_as_string) {
     values_as_strings.push_back(value_as_string);
+    // To make it possible to compare
+    std::sort(values_as_strings.begin(), values_as_strings.end());
   }
 
-  std::vector<std::string> values_as_strings;
+  bool operator==(const AttributeDescriptor& as) const {
+    return ((as.attribute_name == attribute_name) &&
+            (as.value_type == value_type) &&
+            (as.values_as_strings == values_as_strings));
+  }
+
+  // Compares attribute name only
+  bool operator<(const AttributeDescriptor& as) const {
+    return attribute_name < as.attribute_name;
+  }
 };
 
 // AttributeModifyDescriptor: Describes one attribute to modify
@@ -207,6 +219,19 @@ struct CreateDescriptor {
   std::vector<AttributeDescriptor> attributes;
   void AddAttribute(AttributeDescriptor one_attribute) {
     attributes.push_back(one_attribute);
+    // To make it possible to compare (sorted on attribute name)
+    std::sort(attributes.begin(), attributes.end());
+  }
+
+  // Compare all variables. All equal is true.
+  // Note: The vectors are compared using vector operator ==. This means that
+  // not only the content must be the same but also the order.
+  // TBD() could be handled by sorting
+  bool operator==(const CreateDescriptor& cd) {
+    return ((cd.ignore_ais_err_exist == ignore_ais_err_exist) &&
+            (cd.class_name == class_name) &&
+            (cd.parent_name == parent_name) &&
+            (cd.attributes == attributes));
   }
 };
 
@@ -248,14 +273,28 @@ struct CcbDescriptor {
   std::vector<ModifyDescriptor> modify_descriptors;
 
   // Use these methods to add the modifications
-  void AddCreate(CreateDescriptor one_create_descriptor) {
-    create_descriptors.push_back(one_create_descriptor);
+
+  // Duplicate descriptors cannot be added. If a duplicate
+  // create descriptor is given as input it will not be added.
+  // Returns false if duplicate
+  bool AddCreate(CreateDescriptor new_create_descriptor) {
+    bool is_added = true;
+    for (auto& stored_create_descriptor : create_descriptors) {
+      if (stored_create_descriptor == new_create_descriptor) {
+        is_added = false;
+        break;
+      }
+    }
+    if (is_added == true)
+      create_descriptors.push_back(new_create_descriptor);
+    return is_added;
   }
-  void AddDelete(DeleteDescriptor one_delete_descriptor) {
-    delete_descriptors.push_back(one_delete_descriptor);
+
+  void AddDelete(DeleteDescriptor new_delete_descriptor) {
+    delete_descriptors.push_back(new_delete_descriptor);
   }
-  void AddModify(ModifyDescriptor one_modify_descriptor) {
-    modify_descriptors.push_back(one_modify_descriptor);
+  void AddModify(ModifyDescriptor new_modify_descriptor) {
+    modify_descriptors.push_back(new_modify_descriptor);
   }
 };
 
diff --git a/src/smf/smfd/imm_modify_demo/ccbhdl_test.cc 
b/src/smf/smfd/imm_modify_demo/test_ccbhdl.cc
similarity index 100%
rename from src/smf/smfd/imm_modify_demo/ccbhdl_test.cc
rename to src/smf/smfd/imm_modify_demo/test_ccbhdl.cc
diff --git a/src/smf/smfd/imm_modify_demo/test_objexist.cc 
b/src/smf/smfd/imm_modify_demo/test_objexist.cc
new file mode 100644
index 000000000..885cc3aa9
--- /dev/null
+++ b/src/smf/smfd/imm_modify_demo/test_objexist.cc
@@ -0,0 +1,127 @@
+/*      -*- OpenSAF  -*-
+ *
+ * Copyright Ericsson AB 2018 - All Rights Reserved.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
+ * under the GNU Lesser General Public License Version 2.1, February 1999.
+ * The complete license can be accessed from the following location:
+ * http://opensource.org/licenses/lgpl-license.php
+ * See the Copying file included with the OpenSAF distribution for full
+ * licensing terms.
+ *
+ * Author(s): Ericsson AB
+ *
+ */
+
+#include <limits.h>
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <utility>
+#include <iostream>
+
+#include "ais/include/saImm.h"
+#include "ais/include/saAis.h"
+#include "base/osaf_extended_name.h"
+
+#include "smf/smfd/SmfUtils_ObjExist.h"
+
+#include "smf/smfd/imm_modify_config/immccb.h"
+
+using namespace std;
+
+int main() {
+  CheckObjectExist e_check;
+  CheckObjectExist::ReturnCode exist_rc;
+
+  printf("Testing");
+
+  cout << "Find an object test:" << endl;
+  modelmodify::CreateDescriptor existing_object;
+  modelmodify::AttributeDescriptor log_config;
+  log_config.attribute_name = "logConfig";
+  log_config.value_type = SA_IMM_ATTR_SASTRINGT;
+  log_config.AddValue("logConfig=1");
+  existing_object.class_name = "OpenSafLogConfig";
+  existing_object.parent_name = "safApp=safLogService";
+  existing_object.AddAttribute(log_config);
+
+  std::string object_dn = "logConfig=1,safApp=safLogService";
+  cout << "Object to check '" << object_dn << "'" << endl;
+  exist_rc = e_check.IsExisting(existing_object);
+  if (exist_rc == e_check.kFail) {
+    cout << "Check failed" << endl;
+  } else if (exist_rc == e_check.kOk) {
+    cout << "Object exist" << endl;
+  } else if (exist_rc == e_check.kNotExist) {
+    cout << "Object does not exist" << endl;
+  } else {
+    cout << "Fail, unknown return code" << endl;
+  }
+  cout << endl;
+
+
+  object_dn = "Kalle";
+  cout << "Object to check '" << object_dn << "'" << endl;
+  log_config.values_as_strings.clear();
+  log_config.AddValue("Kalle");
+  existing_object.attributes.clear();
+  existing_object.AddAttribute(log_config);
+  exist_rc = e_check.IsExisting(existing_object);
+  if (exist_rc == e_check.kFail) {
+    cout << "Check failed" << endl;
+  } else if (exist_rc == e_check.kOk) {
+    cout << "Object exist" << endl;
+  } else if (exist_rc == e_check.kNotExist) {
+    cout << "Object does not exist" << endl;
+  } else {
+    cout << "Fail, unknown return code" << endl;
+  }
+  cout << endl;
+
+
+  object_dn = "logConfig=1";
+  cout << "Object to check '" << object_dn << "'" << endl;
+  log_config.values_as_strings.clear();
+  log_config.AddValue("logConfig=1");
+  existing_object.attributes.clear();
+  existing_object.parent_name.clear();
+  existing_object.AddAttribute(log_config);
+  exist_rc = e_check.IsExisting(existing_object);
+  if (exist_rc == e_check.kFail) {
+    cout << "Check failed" << endl;
+  } else if (exist_rc == e_check.kOk) {
+    cout << "Object exist" << endl;
+  } else if (exist_rc == e_check.kNotExist) {
+    cout << "Object does not exist" << endl;
+  } else {
+    cout << "Fail, unknown return code" << endl;
+  }
+  cout << endl;
+
+
+  object_dn = "";
+  cout << "Object to check '" << object_dn << "'" << endl;
+  log_config.values_as_strings.clear();
+  //log_config.AddValue("logConfig=1");
+  existing_object.attributes.clear();
+  existing_object.parent_name.clear();
+  existing_object.AddAttribute(log_config);
+  exist_rc = e_check.IsExisting(existing_object);
+  if (exist_rc == e_check.kFail) {
+    cout << "Check failed" << endl;
+  } else if (exist_rc == e_check.kOk) {
+    cout << "Object exist" << endl;
+  } else if (exist_rc == e_check.kNotExist) {
+    cout << "Object does not exist" << endl;
+  } else {
+    cout << "Fail, unknown return code" << endl;
+  }
+  cout << endl;
+
+
+  return 0;
+}
\ No newline at end of file
-- 
2.17.0


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

Reply via email to