Remove NTPServers duplicate values and null values

When saving the set NTPServers values from webUI, NTPServer may contain
duplicate values and null values and update them to D-Bus.

Now, need to parse and verify the value of the ntpServers attribute,and
remove duplicate values and null values.

Tested:save NTP and check it via D-Bus
without this patch:
NTPServers  property  as  3 "" "10.164.29.2" "10.164.29.2"

with this patch:
NTPServers  property  as  2 "" "10.164.29.2"

Signed-off-by: George Liu <liuxiwei@inspur.com>
Change-Id: I52291e4608efd635b179f3934c3d3e805afd2209
diff --git a/meson.build b/meson.build
index 7673112..863cad1 100644
--- a/meson.build
+++ b/meson.build
@@ -359,6 +359,7 @@
   'redfish-core/ut/lock_test.cpp',
   'redfish-core/ut/configfile_test.cpp',
   'redfish-core/ut/time_utils_test.cpp',
+  'redfish-core/ut/stl_utils_test.cpp',
   'redfish-core/ut/hex_utils_test.cpp',
   'http/ut/utility_test.cpp'
 ]
diff --git a/redfish-core/include/utils/stl_utils.hpp b/redfish-core/include/utils/stl_utils.hpp
new file mode 100644
index 0000000..04d02cb
--- /dev/null
+++ b/redfish-core/include/utils/stl_utils.hpp
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <algorithm>
+#include <string>
+
+namespace redfish
+{
+
+namespace stl_utils
+{
+
+template <typename ForwardIterator>
+ForwardIterator firstDuplicate(ForwardIterator first, ForwardIterator last)
+{
+    auto newLast = first;
+
+    for (auto current = first; current != last; ++current)
+    {
+        if (std::find(first, newLast, *current) == newLast)
+        {
+            if (newLast != current)
+            {
+                *newLast = *current;
+            }
+            ++newLast;
+        }
+    }
+
+    return newLast;
+}
+
+template <typename T>
+void removeDuplicate(T& t)
+{
+    t.erase(firstDuplicate(t.begin(), t.end()), t.end());
+}
+
+} // namespace stl_utils
+} // namespace redfish
diff --git a/redfish-core/lib/network_protocol.hpp b/redfish-core/lib/network_protocol.hpp
index a06611f..0d93102 100644
--- a/redfish-core/lib/network_protocol.hpp
+++ b/redfish-core/lib/network_protocol.hpp
@@ -22,6 +22,7 @@
 #include <app.hpp>
 #include <registries/privilege_registry.hpp>
 #include <utils/json_utils.hpp>
+#include <utils/stl_utils.hpp>
 
 #include <optional>
 #include <variant>
@@ -237,9 +238,19 @@
 }
 
 inline void
-    handleNTPServersPatch(const std::vector<std::string>& ntpServers,
-                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
+    handleNTPServersPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+                          std::vector<std::string>& ntpServers)
 {
+    auto iter = stl_utils::firstDuplicate(ntpServers.begin(), ntpServers.end());
+    if (iter != ntpServers.end())
+    {
+        std::string pointer =
+            "NTPServers/" +
+            std::to_string(std::distance(ntpServers.begin(), iter));
+        messages::propertyValueIncorrect(asyncResp->res, pointer, *iter);
+        return;
+    }
+
     crow::connections::systemBus->async_method_call(
         [asyncResp](const boost::system::error_code ec) {
             if (ec)
@@ -393,12 +404,8 @@
 
                     if (ntpServers)
                     {
-                        std::sort((*ntpServers).begin(), (*ntpServers).end());
-                        (*ntpServers)
-                            .erase(std::unique((*ntpServers).begin(),
-                                               (*ntpServers).end()),
-                                   (*ntpServers).end());
-                        handleNTPServersPatch(*ntpServers, asyncResp);
+                        stl_utils::removeDuplicate(*ntpServers);
+                        handleNTPServersPatch(asyncResp, *ntpServers);
                     }
                 }
 
diff --git a/redfish-core/ut/stl_utils_test.cpp b/redfish-core/ut/stl_utils_test.cpp
new file mode 100644
index 0000000..a5115bd
--- /dev/null
+++ b/redfish-core/ut/stl_utils_test.cpp
@@ -0,0 +1,21 @@
+#include "utils/stl_utils.hpp"
+
+#include <gmock/gmock.h>
+
+TEST(STLUtilesTest, RemoveDuplicates)
+{
+    std::vector<std::string> strVec = {"s1", "s4", "s1", "s2", "", "s3", "s3"};
+
+    auto iter =
+        redfish::stl_utils::firstDuplicate(strVec.begin(), strVec.end());
+    EXPECT_EQ(*iter, "s3");
+
+    redfish::stl_utils::removeDuplicate(strVec);
+
+    EXPECT_EQ(strVec.size(), 5);
+    EXPECT_EQ(strVec[0], "s1");
+    EXPECT_EQ(strVec[1], "s4");
+    EXPECT_EQ(strVec[2], "s2");
+    EXPECT_EQ(strVec[3], "");
+    EXPECT_EQ(strVec[4], "s3");
+}