inventory: implement deserialization

Use Cereal to deserialize inventory information persisted in the
filesystem and restore that to create inventory d-bus objects. Perform
the restore when the app starts.

Change-Id: I0f36a9cbdde223e4bfd9e178e33f5677217ba881
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
diff --git a/manager.cpp b/manager.cpp
index 86b1757..6049161 100644
--- a/manager.cpp
+++ b/manager.cpp
@@ -18,6 +18,7 @@
 #include <chrono>
 #include <algorithm>
 #include <phosphor-logging/log.hpp>
+#include <experimental/filesystem>
 #include "manager.hpp"
 #include "errors.hpp"
 
@@ -103,6 +104,9 @@
     }
 
     _bus.request_name(busname);
+
+    // Restore any persistent inventory
+    restore();
 }
 
 void Manager::shutdown() noexcept
@@ -146,7 +150,8 @@
     const sdbusplus::message::object_path& path,
     const Object& interfaces,
     ObjectReferences::iterator pos,
-    bool newObject)
+    bool newObject,
+    bool restoreFromCache)
 {
     auto& refaces = pos->second;
     auto ifaceit = interfaces.cbegin();
@@ -200,8 +205,16 @@
                 auto& assign = std::get<AssignerType>(opsit->second);
                 assign(ifaceit->second, refaceit->second);
             }
-            auto& serialize = std::get<SerializerType>(opsit->second);
-            serialize(path, ifaceit->first, refaceit->second);
+            if (!restoreFromCache)
+            {
+                auto& serialize = std::get<SerializerType>(opsit->second);
+                serialize(path, ifaceit->first, refaceit->second);
+            }
+            else
+            {
+                auto& deserialize = std::get<DeserializerType>(opsit->second);
+                deserialize(path, ifaceit->first, refaceit->second);
+            }
         }
         catch (const InterfaceError& e)
         {
@@ -225,7 +238,8 @@
 }
 
 void Manager::updateObjects(
-    const std::map<sdbusplus::message::object_path, Object>& objs)
+    const std::map<sdbusplus::message::object_path, Object>& objs,
+    bool restoreFromCache)
 {
     auto objit = objs.cbegin();
     auto refit = _refs.begin();
@@ -255,7 +269,8 @@
             newObj = true;
         }
 
-        updateInterfaces(absPath, objit->second, refit, newObj);
+        updateInterfaces(absPath, objit->second, refit, newObj,
+                         restoreFromCache);
         ++objit;
     }
 }
@@ -331,6 +346,50 @@
     return iit->second;
 }
 
+void Manager::restore()
+{
+    namespace fs = std::experimental::filesystem;
+
+    if (!fs::exists(fs::path(PIM_PERSIST_PATH)))
+    {
+        return;
+    }
+
+    static const std::string remove =
+        std::string(PIM_PERSIST_PATH) + INVENTORY_ROOT;
+
+    std::map<sdbusplus::message::object_path, Object> objects;
+    for (const auto& dirent :
+         fs::recursive_directory_iterator(PIM_PERSIST_PATH))
+    {
+        const auto& path = dirent.path();
+        if (fs::is_regular_file(path))
+        {
+            auto ifaceName = path.filename().string();
+            auto objPath = path.parent_path().string();
+            objPath.erase(0, remove.length());
+            auto objit = objects.find(objPath);
+            Interface propertyMap{};
+            if (objects.end() != objit)
+            {
+                auto& object = objit->second;
+                object.emplace(std::move(ifaceName), std::move(propertyMap));
+            }
+            else
+            {
+                Object object;
+                object.emplace(std::move(ifaceName), std::move(propertyMap));
+                objects.emplace(std::move(objPath), std::move(object));
+            }
+        }
+    }
+    if (!objects.empty())
+    {
+        auto restoreFromCache = true;
+        updateObjects(objects, restoreFromCache);
+    }
+}
+
 } // namespace manager
 } // namespace inventory
 } // namespace phosphor