PEL: Use class to watch properties in DataIface

Instead of having the DataInterface class explicitly watch for all of
the PropertiesChanged and InterfacesAdded signals for the D-Bus
properties it needs the values of, create some classes to wrap that
functionality.

The PropertyWatcher class will call a user defined function, passing it
the property value for the path/interface/property specified in the
following cases:
1) On construction, by making a property read method call, if the
   property is on D-Bus then.
2) On a properties changed signal for that property.
3) On an interfaces added signal for that property's interface.

The InterfaceWatcher class will call a user defined function, passing it
the property name/value map for all properties in that interface, in the
following cases:
1) On construction, by making a GetAll property read method call, if the
   interface is on D-Bus then.
2) On a properties changed signal for that interface.
3) On an interfaces added signal for that interface.

Both of these are derived from the DBusWatcher class, and the
DataInterface will store a vector of DBusWatcher pointers after it
creates the instances of the PropertyWatcher or InterfaceWatcher classes
in its constructor.

This commit changes the current properties being watched - the system
model, the system serial number, and the operating system status to this
method.

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: Iade4ac89a9ce1d46bdebf353350bf161722ced9f
diff --git a/extensions/openpower-pels/data_interface.cpp b/extensions/openpower-pels/data_interface.cpp
index 3342569..deb4ba4 100644
--- a/extensions/openpower-pels/data_interface.cpp
+++ b/extensions/openpower-pels/data_interface.cpp
@@ -51,70 +51,50 @@
 
 DataInterface::DataInterface(sdbusplus::bus::bus& bus) : _bus(bus)
 {
-    readMTMS();
-    readHostState();
     readBMCFWVersion();
     readServerFWVersion();
     readBMCFWVersionID();
+
+    // Watch both the Model and SN properties on the system's Asset iface
+    _properties.emplace_back(std::make_unique<InterfaceWatcher<DataInterface>>(
+        bus, object_path::systemInv, interface::invAsset, *this,
+        [this](const auto& properties) {
+            auto model = properties.find("Model");
+            if (model != properties.end())
+            {
+                this->_machineTypeModel = std::get<std::string>(model->second);
+            }
+
+            auto sn = properties.find("SerialNumber");
+            if (sn != properties.end())
+            {
+                this->_machineSerialNumber = std::get<std::string>(sn->second);
+            }
+        }));
+
+    // Watch the OperatingSystemState property
+    _properties.emplace_back(std::make_unique<PropertyWatcher<DataInterface>>(
+        bus, object_path::hostState, interface::osStatus,
+        "OperatingSystemState", *this, [this](const auto& value) {
+            auto status =
+                Status::convertOSStatusFromString(std::get<std::string>(value));
+
+            if ((status == Status::OSStatus::BootComplete) ||
+                (status == Status::OSStatus::Standby))
+            {
+                setHostState(true);
+            }
+            else
+            {
+                setHostState(false);
+            }
+        }));
 }
 
-void DataInterface::readMTMS()
-{
-    // If this runs when the inventory service isn't running, it will get the
-    // value whenever it starts via the propertiesChanged callback.
-    try
-    {
-        auto inventoryService =
-            getService(object_path::systemInv, interface::invAsset);
-
-        if (!inventoryService.empty())
-        {
-            auto properties = getAllProperties(
-                inventoryService, object_path::systemInv, interface::invAsset);
-
-            _machineTypeModel = std::get<std::string>(properties["Model"]);
-
-            _machineSerialNumber =
-                std::get<std::string>(properties["SerialNumber"]);
-        }
-    }
-    catch (std::exception& e)
-    {
-        // Inventory must not be running at this moment.
-    }
-
-    // Keep up to date by watching for the propertiesChanged signal.
-    _sysInventoryPropMatch = std::make_unique<sdbusplus::bus::match_t>(
-        _bus,
-        sdbusplus::bus::match::rules::propertiesChanged(object_path::systemInv,
-                                                        interface::invAsset),
-        std::bind(std::mem_fn(&DataInterface::sysAssetPropChanged), this,
-                  std::placeholders::_1));
-}
-
-void DataInterface::sysAssetPropChanged(sdbusplus::message::message& msg)
-{
-    DBusInterface interface;
-    DBusPropertyMap properties;
-
-    msg.read(interface, properties);
-
-    auto model = properties.find("Model");
-    if (model != properties.end())
-    {
-        _machineTypeModel = std::get<std::string>(model->second);
-    }
-
-    auto sn = properties.find("SerialNumber");
-    if (sn != properties.end())
-    {
-        _machineSerialNumber = std::get<std::string>(sn->second);
-    }
-}
-
-DBusPropertyMap DataInterface::getAllProperties(const std::string& service,
-                                                const std::string& objectPath,
-                                                const std::string& interface)
+DBusPropertyMap
+    DataInterface::getAllProperties(const std::string& service,
+                                    const std::string& objectPath,
+                                    const std::string& interface) const
 {
     DBusPropertyMap properties;
 
@@ -131,7 +111,8 @@
 void DataInterface::getProperty(const std::string& service,
                                 const std::string& objectPath,
                                 const std::string& interface,
-                                const std::string& property, DBusValue& value)
+                                const std::string& property,
+                                DBusValue& value) const
 {
 
     auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(),
@@ -164,67 +145,6 @@
     return std::string{};
 }
 
-void DataInterface::readHostState()
-{
-    _hostUp = false;
-
-    try
-    {
-        auto service = getService(object_path::hostState, interface::osStatus);
-        if (!service.empty())
-        {
-            DBusValue value;
-            getProperty(service, object_path::hostState, interface::osStatus,
-                        "OperatingSystemState", value);
-
-            auto status =
-                Status::convertOSStatusFromString(std::get<std::string>(value));
-
-            if ((status == Status::OSStatus::BootComplete) ||
-                (status == Status::OSStatus::Standby))
-            {
-                _hostUp = true;
-            }
-        }
-    }
-    catch (std::exception& e)
-    {
-        // Not available yet.
-    }
-
-    // Keep up to date by watching for the propertiesChanged signal.
-    _osStateMatch = std::make_unique<sdbusplus::bus::match_t>(
-        _bus,
-        sdbusplus::bus::match::rules::propertiesChanged(object_path::hostState,
-                                                        interface::osStatus),
-        std::bind(std::mem_fn(&DataInterface::osStatePropChanged), this,
-                  std::placeholders::_1));
-}
-
-void DataInterface::osStatePropChanged(sdbusplus::message::message& msg)
-{
-    DBusInterface interface;
-    DBusPropertyMap properties;
-
-    msg.read(interface, properties);
-
-    auto state = properties.find("OperatingSystemState");
-    if (state != properties.end())
-    {
-        auto status = Status::convertOSStatusFromString(
-            std::get<std::string>(state->second));
-
-        bool newHostState = false;
-        if ((status == Status::OSStatus::BootComplete) ||
-            (status == Status::OSStatus::Standby))
-        {
-            newHostState = true;
-        }
-
-        setHostState(newHostState);
-    }
-}
-
 uint8_t DataInterface::getPLDMInstanceID(uint8_t eid) const
 {
     return 0;