Add property watches

Property watches cache DBus property values given an externally
supplied index of property names and paths, in an externally
supplied storage location.

Change-Id: I155081da88c3ab0e4f6a13b012fc9719203b1888
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
diff --git a/src/propertywatch.hpp b/src/propertywatch.hpp
new file mode 100644
index 0000000..59db599
--- /dev/null
+++ b/src/propertywatch.hpp
@@ -0,0 +1,167 @@
+/**
+ * @file propertywatch.hpp
+ * @brief PropertyWatch class declarations.
+ *
+ * In general class users should include propertywatchimpl.hpp instead to avoid
+ * link failures.
+ */
+#pragma once
+
+#include "data_types.hpp"
+#include "watch.hpp"
+
+namespace phosphor
+{
+namespace dbus
+{
+namespace monitoring
+{
+
+/** @class PropertyWatch
+ *  @brief Type agnostic, factored out logic for property watches.
+ *
+ *  A property watch maintains the state of one or more DBus properties
+ *  as specified by the supplied index.
+ */
+template <typename DBusInterfaceType>
+class PropertyWatch : public Watch
+{
+    public:
+        PropertyWatch() = delete;
+        PropertyWatch(const PropertyWatch&) = delete;
+        PropertyWatch(PropertyWatch&&) = default;
+        PropertyWatch& operator=(const PropertyWatch&) = delete;
+        PropertyWatch& operator=(PropertyWatch&&) = default;
+        virtual ~PropertyWatch() = default;
+        explicit PropertyWatch(const PropertyIndex& watchIndex)
+            : Watch(), index(watchIndex), alreadyRan(false) {}
+
+        /** @brief Start the watch.
+         *
+         *  Watch start interface implementation for PropertyWatch.
+         */
+        void start() override;
+
+        /** @brief Update properties.
+         *
+         *  Subclasses to query the properties specified by the index
+         *  and update the cache.
+         *
+         *  @param[in] busName - The busname hosting the interface to query.
+         *  @param[in] path - The path of the interface to query.
+         *  @param[in] interface - The interface to query.
+         */
+        virtual void updateProperties(
+            const std::string& busName,
+            const std::string& path,
+            const std::string& interface) = 0;
+
+        /** @brief Dbus signal callback for PropertiesChanged.
+         *
+         *  Subclasses to update the cache.
+         *
+         *  @param[in] message - The org.freedesktop.DBus.PropertiesChanged
+         *               message.
+         *  @param[in] path - The path associated with the message.
+         *  @param[in] interface - The interface associated with the message.
+         */
+        virtual void propertiesChanged(
+            sdbusplus::message::message&,
+            const std::string& path,
+            const std::string& interface) = 0;
+
+        /** @brief Dbus signal callback for InterfacesAdded.
+         *
+         *  Subclasses to update the cache.
+         *
+         *  @param[in] msg - The org.freedesktop.DBus.PropertiesChanged
+         *               message.
+         */
+        virtual void interfacesAdded(sdbusplus::message::message& msg) = 0;
+
+    protected:
+
+        /** @brief Property names and their associated storage. */
+        const PropertyIndex& index;
+
+    private:
+
+        /** @brief The start method should only be invoked once. */
+        bool alreadyRan;
+};
+
+/** @class PropertyWatchOfType
+ *  @brief Type specific logic for PropertyWatch.
+ *
+ *  @tparam DBusInterfaceType - DBus access delegate.
+ *  @tparam T - The type of the properties being watched.
+ */
+template <typename T, typename DBusInterfaceType>
+class PropertyWatchOfType : public PropertyWatch<DBusInterfaceType>
+{
+    public:
+        PropertyWatchOfType() = default;
+        PropertyWatchOfType(const PropertyWatchOfType&) = delete;
+        PropertyWatchOfType(PropertyWatchOfType&&) = default;
+        PropertyWatchOfType& operator=(const PropertyWatchOfType&) = delete;
+        PropertyWatchOfType& operator=(PropertyWatchOfType&&) = default;
+        ~PropertyWatchOfType() = default;
+        explicit PropertyWatchOfType(
+            const PropertyIndex& watchIndex) :
+            PropertyWatch<DBusInterfaceType>(watchIndex) {}
+
+        /** @brief PropertyMatch implementation for PropertyWatchOfType.
+         *
+         *  @param[in] busName - The busname hosting the interface to query.
+         *  @param[in] path - The path of the interface to query.
+         *  @param[in] interface - The interface to query.
+         */
+        void updateProperties(
+            const std::string& busName,
+            const std::string& path,
+            const std::string& interface) override;
+
+        /** @brief PropertyMatch implementation for PropertyWatchOfType.
+         *
+         *  @param[in] msg - The org.freedesktop.DBus.PropertiesChanged
+         *               message.
+         *  @param[in] path - The path associated with the message.
+         *  @param[in] interface - The interface associated with the message.
+         */
+        void propertiesChanged(
+            sdbusplus::message::message& msg,
+            const std::string& path,
+            const std::string& interface) override;
+
+        /** @brief DBus agnostic implementation of interfacesAdded.
+         *
+         *  @param[in] path - The path of the properties that changed.
+         *  @param[in] interface - The interface of the properties that
+         *                  changed.
+         *  @param[in] properites - The properties that changed.
+         */
+        void propertiesChanged(
+            const std::string& path,
+            const std::string& interface,
+            const PropertiesChanged<T>& properties);
+
+        /** @brief PropertyMatch implementation for PropertyWatchOfType.
+         *
+         *  @param[in] msg - The org.freedesktop.DBus.PropertiesChanged
+         *               message.
+         */
+        void interfacesAdded(sdbusplus::message::message& msg) override;
+
+        /** @brief DBus agnostic implementation of interfacesAdded.
+         *
+         *  @param[in] path - The path of the added interfaces.
+         *  @param[in] interfaces - The added interfaces.
+         */
+        void interfacesAdded(
+            const std::string& path,
+            const InterfacesAdded<T>& interfaces);
+};
+
+} // namespace monitoring
+} // namespace dbus
+} // namespace phosphor