Link watches to callbacks

Callbacks must ultimately be triggered when a property
is updated by a watch.  Add that support.

Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
Change-Id: I20130a11c19ddcf2c4ae45800f2068b31950bcd6
diff --git a/src/example/example.yaml b/src/example/example.yaml
index 65f6537..2066227 100644
--- a/src/example/example.yaml
+++ b/src/example/example.yaml
@@ -48,11 +48,14 @@
 - name: example property watch
   description: >
     'A property watch instructs PDM to maintain a cache of the state
-    of the specified properties on the specified DBus objects.'
+    of the specified properties on the specified DBus objects.
+
+    An optional callback can be triggered when property values change.'
   class: watch
   watch: property
   paths: example path group
   properties: example property group
+  callback: example count condition
 
 - name: example journal callback
   description: >
diff --git a/src/pdmgen.py b/src/pdmgen.py
index 4a958e1..54790bb 100755
--- a/src/pdmgen.py
+++ b/src/pdmgen.py
@@ -410,8 +410,21 @@
     '''Handle the property watch config file directive.'''
 
     def __init__(self, *a, **kw):
+        self.callback = kw.pop('callback', None)
         super(PropertyWatch, self).__init__(**kw)
 
+    def setup(self, objs):
+        '''Resolve optional callback.'''
+
+        if self.callback:
+            self.callback = get_index(
+                objs,
+                'callback',
+                self.callback,
+                config=self.configfile)
+
+        super(PropertyWatch, self).setup(objs)
+
 
 class Callback(HasPropertyIndex):
     '''Interface and common logic for callbacks.'''
diff --git a/src/propertywatch.hpp b/src/propertywatch.hpp
index 59db599..3eb05df 100644
--- a/src/propertywatch.hpp
+++ b/src/propertywatch.hpp
@@ -17,6 +17,8 @@
 namespace monitoring
 {
 
+class Callback;
+
 /** @class PropertyWatch
  *  @brief Type agnostic, factored out logic for property watches.
  *
@@ -33,8 +35,10 @@
         PropertyWatch& operator=(const PropertyWatch&) = delete;
         PropertyWatch& operator=(PropertyWatch&&) = default;
         virtual ~PropertyWatch() = default;
-        explicit PropertyWatch(const PropertyIndex& watchIndex)
-            : Watch(), index(watchIndex), alreadyRan(false) {}
+        PropertyWatch(
+            const PropertyIndex& watchIndex,
+            Callback* cb = nullptr)
+            : Watch(), index(watchIndex), callback(cb), alreadyRan(false) {}
 
         /** @brief Start the watch.
          *
@@ -84,7 +88,8 @@
         /** @brief Property names and their associated storage. */
         const PropertyIndex& index;
 
-    private:
+        /** @brief Optional callback method. */
+        Callback* const callback;
 
         /** @brief The start method should only be invoked once. */
         bool alreadyRan;
@@ -106,9 +111,13 @@
         PropertyWatchOfType& operator=(const PropertyWatchOfType&) = delete;
         PropertyWatchOfType& operator=(PropertyWatchOfType&&) = default;
         ~PropertyWatchOfType() = default;
-        explicit PropertyWatchOfType(
+        PropertyWatchOfType(
+            const PropertyIndex& watchIndex, Callback& callback) :
+            PropertyWatch<DBusInterfaceType>(watchIndex, &callback) {}
+        PropertyWatchOfType(
             const PropertyIndex& watchIndex) :
-            PropertyWatch<DBusInterfaceType>(watchIndex) {}
+            PropertyWatch<DBusInterfaceType>(watchIndex, nullptr) {}
+
 
         /** @brief PropertyMatch implementation for PropertyWatchOfType.
          *
diff --git a/src/propertywatchimpl.hpp b/src/propertywatchimpl.hpp
index 6e957ae..d0153e4 100644
--- a/src/propertywatchimpl.hpp
+++ b/src/propertywatchimpl.hpp
@@ -3,6 +3,7 @@
 #include <sdbusplus/message.hpp>
 #include <sdbusplus/bus/match.hpp>
 #include <vector>
+#include "callback.hpp"
 #include "data_types.hpp"
 #include "propertywatch.hpp"
 
@@ -141,6 +142,12 @@
         }
 
         std::get<2>(item->second).get() = p.second.template get<T>();
+
+        // Invoke callback if present.
+        if (this->alreadyRan && this->callback)
+        {
+            (*this->callback)();
+        }
     }
 }
 
diff --git a/src/templates/generated.mako.hpp b/src/templates/generated.mako.hpp
index a4819e2..15835bf 100644
--- a/src/templates/generated.mako.hpp
+++ b/src/templates/generated.mako.hpp
@@ -188,7 +188,12 @@
         {
 % for w in watches:
             std::make_unique<PropertyWatchOfType<${w.datatype}, SDBusPlus>>(
+    % if w.callback is None:
                 ConfigPropertyIndicies::get()[${w.instances}]),
+    % else:
+                ConfigPropertyIndicies::get()[${w.instances}],
+                *ConfigPropertyCallbacks::get()[${w.callback}]),
+    % endif
 % endfor
         };
         return propertyWatches;