update: Refactor to use ndn-cxx dispatcher for prefix update/readvertise

refs: #3728

Change-Id: I3186433ed460850753f033a1d03fe27fd1fe889c
diff --git a/src/conf-file-processor.cpp b/src/conf-file-processor.cpp
index 9facbd5..c80f439 100644
--- a/src/conf-file-processor.cpp
+++ b/src/conf-file-processor.cpp
@@ -503,10 +503,8 @@
         std::string uriString = CommandAttriTree.get<std::string>("face-uri");
 
         ndn::util::FaceUri faceUri;
-        try {
-          faceUri = ndn::util::FaceUri(uriString);
-        } catch (const ndn::util::FaceUri::Error& e) {
-          std::cerr << "Malformed face-uri <" << uriString << "> for " << name << std::endl;
+        if (! faceUri.parse(uriString)) {
+          std::cerr << "parsing failed!" << std::endl;
           return false;
         }
 
@@ -554,11 +552,10 @@
   }
 
   try {
-    /* Radius and angle(s) are mandatory configuration parameters in hyperbolic section.
-     * Even if router can have hyperbolic routing calculation off but other router
-     * in the network may use hyperbolic routing calculation for FIB generation.
-     * So each router need to advertise its hyperbolic coordinates in the network
-     */
+    // Radius and angle(s) are mandatory configuration parameters in hyperbolic section.
+    // Even if router can have hyperbolic routing calculation off but other router
+    // in the network may use hyperbolic routing calculation for FIB generation.
+    // So each router need to advertise its hyperbolic coordinates in the network
     double radius = section.get<double>("radius");
     std::string angleString = section.get<std::string>("angle");
 
@@ -567,11 +564,9 @@
 
     double angle;
 
-    while (ss >> angle)
-    {
+    while (ss >> angle) {
       angles.push_back(angle);
-      if (ss.peek() == ',' || ss.peek() == ' ')
-      {
+      if (ss.peek() == ',' || ss.peek() == ' ') {
         ss.ignore();
       }
     }
@@ -663,7 +658,6 @@
 
   it++;
   if (it != section.end() && it->first == "prefix-update-validator") {
-    m_nlsr.getPrefixUpdateProcessor().enable();
     m_nlsr.getPrefixUpdateProcessor().loadValidator(it->second, m_confFileName);
 
     it++;
diff --git a/src/nlsr.cpp b/src/nlsr.cpp
index 5709313..c4658e8 100644
--- a/src/nlsr.cpp
+++ b/src/nlsr.cpp
@@ -19,16 +19,16 @@
  * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  **/
 
+#include "nlsr.hpp"
+#include "adjacent.hpp"
+#include "logger.hpp"
+
 #include <cstdlib>
 #include <string>
 #include <sstream>
 #include <cstdio>
 #include <unistd.h>
 
-#include "nlsr.hpp"
-#include "adjacent.hpp"
-#include "logger.hpp"
-
 #include <ndn-cxx/util/face-uri.hpp>
 
 namespace nlsr {
@@ -70,7 +70,8 @@
   , m_validator(m_nlsrFace, DEFAULT_BROADCAST_PREFIX, m_certificateCache, m_certStore)
   , m_controller(m_nlsrFace, m_keyChain, m_validator)
   , m_faceDatasetController(m_nlsrFace, m_keyChain)
-  , m_prefixUpdateProcessor(m_nlsrFace,
+  , m_prefixUpdateProcessor(m_localhostDispatcher,
+                            m_nlsrFace,
                             m_namePrefixList,
                             m_nlsrLsdb,
                             DEFAULT_BROADCAST_PREFIX,
@@ -113,10 +114,6 @@
 void
 Nlsr::onLocalhostRegistrationSuccess(const ndn::Name& name)
 {
-  _LOG_DEBUG("Successfully registered local prefix: " << name);
-
-  m_prefixUpdateProcessor.startListening();
-  m_nfdRibCommandProcessor.startListening();
   // All dispatcher-related sub-prefixes *must* be registered before
   // the top-level prefixes are added.
   try {
diff --git a/src/nlsr.hpp b/src/nlsr.hpp
index bb67f2d..1a3432a 100644
--- a/src/nlsr.hpp
+++ b/src/nlsr.hpp
@@ -22,21 +22,6 @@
 #ifndef NLSR_NLSR_HPP
 #define NLSR_NLSR_HPP
 
-#include <boost/cstdint.hpp>
-#include <stdexcept>
-#include <boost/throw_exception.hpp>
-
-#include <ndn-cxx/face.hpp>
-#include <ndn-cxx/security/key-chain.hpp>
-#include <ndn-cxx/security/certificate-cache-ttl.hpp>
-#include <ndn-cxx/util/scheduler.hpp>
-#include <ndn-cxx/mgmt/nfd/face-event-notification.hpp>
-#include <ndn-cxx/mgmt/nfd/face-monitor.hpp>
-#include <ndn-cxx/mgmt/dispatcher.hpp>
-#include <ndn-cxx/mgmt/nfd/face-status.hpp>
-#include <ndn-cxx/data.hpp>
-#include <ndn-cxx/encoding/block.hpp>
-
 #include "adjacency-list.hpp"
 #include "common.hpp"
 #include "conf-parameter.hpp"
@@ -54,6 +39,22 @@
 #include "update/nfd-rib-command-processor.hpp"
 #include "utility/name-helper.hpp"
 
+#include <stdexcept>
+
+#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/security/certificate-cache-ttl.hpp>
+#include <ndn-cxx/util/scheduler.hpp>
+#include <ndn-cxx/mgmt/nfd/face-event-notification.hpp>
+#include <ndn-cxx/mgmt/nfd/face-monitor.hpp>
+#include <ndn-cxx/mgmt/dispatcher.hpp>
+#include <ndn-cxx/mgmt/nfd/face-status.hpp>
+#include <ndn-cxx/data.hpp>
+#include <ndn-cxx/encoding/block.hpp>
+
+#include <boost/cstdint.hpp>
+#include <boost/throw_exception.hpp>
+
 namespace nlsr {
 
 static ndn::Name DEFAULT_BROADCAST_PREFIX("/ndn/broadcast");
@@ -334,13 +335,13 @@
   }
 
   ndn::mgmt::Dispatcher&
-  getDispatcher()
+  getLocalhostDispatcher()
   {
     return m_localhostDispatcher;
   }
 
   ndn::mgmt::Dispatcher&
-  getDispatcherRouterName()
+  getRouterNameDispatcher()
   {
     return m_routerNameDispatcher;
   }
@@ -446,6 +447,7 @@
   RoutingTable m_routingTable;
   Fib m_fib;
   NamePrefixTable m_namePrefixTable;
+
   ndn::mgmt::Dispatcher m_localhostDispatcher;
   ndn::mgmt::Dispatcher m_routerNameDispatcher;
 
diff --git a/src/update/manager-base.cpp b/src/update/manager-base.cpp
new file mode 100644
index 0000000..47ff076
--- /dev/null
+++ b/src/update/manager-base.cpp
@@ -0,0 +1,92 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2017,  The University of Memphis,
+ *                           Regents of the University of California,
+ *                           Arizona Board of Regents.
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "manager-base.hpp"
+#include <iostream>
+
+namespace nlsr {
+namespace update {
+
+INIT_LOGGER("UpdatePrefixCommandProcessor");
+
+ManagerBase::ManagerBase(ndn::mgmt::Dispatcher& dispatcher,
+                         const std::string& module)
+  : m_dispatcher(dispatcher)
+  , m_module(module)
+{
+}
+
+ndn::PartialName
+ManagerBase::makeRelPrefix(const std::string& verb) const
+{
+  return ndn::PartialName(m_module).append(verb);
+}
+
+CommandManagerBase::CommandManagerBase(ndn::mgmt::Dispatcher& dispatcher,
+                                      NamePrefixList& namePrefixList,
+                                      Lsdb& lsdb,
+                                      const std::string& module)
+  : ManagerBase(dispatcher, module)
+  , m_namePrefixList(namePrefixList)
+  , m_lsdb(lsdb)
+{
+}
+
+void
+CommandManagerBase::advertiseAndInsertPrefix(const ndn::Name& prefix,
+                                             const ndn::Interest& interest,
+                                             const ndn::mgmt::ControlParameters& parameters,
+                                             const ndn::mgmt::CommandContinuation& done)
+    {
+  const ndn::nfd::ControlParameters& castParams =
+    static_cast<const ndn::nfd::ControlParameters&>(parameters);
+
+  // Only build a Name LSA if the added name is new
+  if (m_namePrefixList.insert(castParams.getName())) {
+    _LOG_INFO("Advertising/Inserting name: " << castParams.getName() << "\n");
+    m_lsdb.buildAndInstallOwnNameLsa();
+    return done(ndn::nfd::ControlResponse(200, "OK").setBody(parameters.wireEncode()));
+  }
+
+  return done(ndn::nfd::ControlResponse(204, "Prefix is already advetised/inserted.").setBody(parameters.wireEncode()));
+}
+
+void
+CommandManagerBase::withdrawAndRemovePrefix(const ndn::Name& prefix,
+                                            const ndn::Interest& interest,
+                                            const ndn::mgmt::ControlParameters& parameters,
+                                            const ndn::mgmt::CommandContinuation& done)
+{
+  const ndn::nfd::ControlParameters& castParams =
+    static_cast<const ndn::nfd::ControlParameters&>(parameters);
+
+  // Only build a Name LSA if the added name is new
+  if (m_namePrefixList.remove(castParams.getName())) {
+    _LOG_INFO("Withdrawing/Removing name: " << castParams.getName() << "\n");
+    m_lsdb.buildAndInstallOwnNameLsa();
+    return done(ndn::nfd::ControlResponse(200, "OK").setBody(parameters.wireEncode()));
+  }
+
+  return done(ndn::nfd::ControlResponse(204, "Prefix is already withdrawn/removed.").setBody(parameters.wireEncode()));
+}
+
+} // namespace update
+} // namespace nlsr
diff --git a/src/update/manager-base.hpp b/src/update/manager-base.hpp
new file mode 100644
index 0000000..33df589
--- /dev/null
+++ b/src/update/manager-base.hpp
@@ -0,0 +1,136 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2017,  The University of Memphis,
+ *                           Regents of the University of California,
+ *                           Arizona Board of Regents.
+ *
+ * This file is part of NLSR (Named-data Link State Routing).
+ * See AUTHORS.md for complete list of NLSR authors and contributors.
+ *
+ * NLSR is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#ifndef NLSR_MANAGER_BASE_HPP
+#define NLSR_MANAGER_BASE_HPP
+
+#include "name-prefix-list.hpp"
+#include "test-access-control.hpp"
+#include "lsdb.hpp"
+#include "nfd-rib-commands.hpp"
+#include "prefix-update-commands.hpp"
+#include "logger.hpp"
+
+#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/interest.hpp>
+#include <ndn-cxx/mgmt/nfd/control-command.hpp>
+#include <ndn-cxx/mgmt/dispatcher.hpp>
+#include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
+#include <ndn-cxx/mgmt/nfd/control-response.hpp>
+
+#include <boost/noncopyable.hpp>
+
+namespace nlsr {
+
+class Lsdb;
+
+namespace update {
+
+class ManagerBase : boost::noncopyable
+{
+public:
+  class Error : public std::runtime_error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : std::runtime_error(what)
+    {
+    }
+  };
+
+public:
+  ManagerBase(ndn::mgmt::Dispatcher& m_dispatcher,
+              const std::string& module);
+
+protected:
+  /*! \brief generate the relative prefix for a handler by appending the verb name to the module name
+   */
+  ndn::PartialName
+  makeRelPrefix(const std::string& verb) const;
+
+PUBLIC_WITH_TESTS_ELSE_PROTECTED:
+  /*! \brief validate the parameters for a given command
+    */
+  template<typename T>
+  bool
+  validateParameters(const ndn::mgmt::ControlParameters& parameters)
+  {
+    const ndn::nfd::ControlParameters* castParams =
+    dynamic_cast<const ndn::nfd::ControlParameters*>(&parameters);
+
+    BOOST_ASSERT(castParams != nullptr);
+    T command;
+    try {
+      command.validateRequest(*castParams);
+    }
+    catch (const ndn::nfd::ControlCommand::ArgumentError& ae) {
+      throw ae;
+    }
+    catch (const std::exception& e) {
+      std::cerr << e.what() << std::endl;
+      return false;
+    }
+    return true;
+  }
+
+protected:
+  ndn::mgmt::Dispatcher& m_dispatcher;
+
+private:
+  std::string m_module;
+};
+
+class CommandManagerBase: public ManagerBase
+{
+public:
+  CommandManagerBase(ndn::mgmt::Dispatcher& m_dispatcher,
+                      NamePrefixList& m_namePrefixList,
+                      Lsdb& lsdb,
+                      const std::string& module);
+
+  /*! \brief add desired name prefix to the advertised name prefix list
+   *         or insert a prefix into the FIB if parameters is valid.
+   */
+  void
+  advertiseAndInsertPrefix(const ndn::Name& prefix,
+                           const ndn::Interest& interest,
+                           const ndn::mgmt::ControlParameters& parameters,
+                           const ndn::mgmt::CommandContinuation& done);
+
+  /*! \brief remove desired name prefix from the advertised name prefix list
+   *         or remove a prefix from the FIB if parameters is valid.
+   */
+  void
+  withdrawAndRemovePrefix(const ndn::Name& prefix,
+                          const ndn::Interest& interest,
+                          const ndn::mgmt::ControlParameters& parameters,
+                          const ndn::mgmt::CommandContinuation& done);
+
+protected:
+  NamePrefixList& m_namePrefixList;
+  Lsdb& m_lsdb;
+};
+
+} // namespace update
+} // namespace nlsr
+
+#endif // NLSR_MANAGER_BASE_HPP
diff --git a/src/update/nfd-rib-command-processor.cpp b/src/update/nfd-rib-command-processor.cpp
index e90503a..23a86eb 100644
--- a/src/update/nfd-rib-command-processor.cpp
+++ b/src/update/nfd-rib-command-processor.cpp
@@ -27,87 +27,20 @@
 
 INIT_LOGGER("NfdRibProcessor");
 
-const ndn::PartialName REGISTER_VERB = ndn::PartialName("rib/register");
-const ndn::PartialName UNREGISTER_VERB = ndn::PartialName("rib/unregister");
-const ndn::Name COMMAND_PREFIX = ndn::Name("/localhost/nlsr");
-
 NfdRibCommandProcessor::NfdRibCommandProcessor(ndn::mgmt::Dispatcher& dispatcher,
-                                               NamePrefixList& namePrefixes,
+                                               NamePrefixList& namePrefixList,
                                                Lsdb& lsdb)
-  : m_dispatcher(dispatcher)
-  , m_namePrefixList(namePrefixes)
-  , m_lsdb(lsdb)
+  : CommandManagerBase(dispatcher, namePrefixList, lsdb, "rib")
 {
-}
+  m_dispatcher.addControlCommand<ndn::nfd::ControlParameters>(makeRelPrefix("register"),
+    ndn::mgmt::makeAcceptAllAuthorization(),
+    std::bind(&NfdRibCommandProcessor::validateParameters<NfdRibRegisterCommand>, this, _1),
+    bind(&NfdRibCommandProcessor::advertiseAndInsertPrefix, this, _1, _2, _3, _4));
 
-void
-NfdRibCommandProcessor::startListening()
-{
-  _LOG_DEBUG("Registering control command prefixes for: " << REGISTER_VERB <<
-             " and " << UNREGISTER_VERB);
-  m_dispatcher.addControlCommand<ndn::nfd::ControlParameters>(REGISTER_VERB,
-                                 ndn::mgmt::makeAcceptAllAuthorization(),
-                                 std::bind(&NfdRibCommandProcessor::validate<NfdRibRegisterCommand>,
-                                           this, _1, REGISTER_VERB),
-                                 [this] (const ndn::Name& prefix, const ndn::Interest& interest,
-                                         const ndn::mgmt::ControlParameters& parameters,
-                                         const ndn::mgmt::CommandContinuation& done) {
-                                   _LOG_DEBUG("Params verified, calling insertPrefix()");
-                                   this->insertPrefix(parameters);
-                                 });
-  m_dispatcher.addControlCommand<ndn::nfd::ControlParameters>(UNREGISTER_VERB,
-                                 ndn::mgmt::makeAcceptAllAuthorization(),
-                                 std::bind(&NfdRibCommandProcessor::validate<NfdRibUnregisterCommand>,
-                                           this, _1, UNREGISTER_VERB),
-                                 [this] (const ndn::Name& prefix, const ndn::Interest& interest,
-                                         const ndn::mgmt::ControlParameters& parameters,
-                                         const ndn::mgmt::CommandContinuation& done) {
-                                   _LOG_DEBUG("Params verified, calling removePrefix()");
-                                   this->removePrefix(parameters);
-                                 });
-}
-
-template<typename T>
-bool
-NfdRibCommandProcessor::validate(const ndn::mgmt::ControlParameters& parameters,
-                                 const ndn::PartialName& command)
-{
-  _LOG_DEBUG("Attempting to verify incoming params for " << command <<
-             " command...");
-  bool wasValidated = true;
-  try {
-      wasValidated = this->validateParameters<T>(parameters);
-  } catch (const ndn::nfd::ControlCommand::ArgumentError& ae) {
-    _LOG_DEBUG("Could not parse params. Message: " << ae.what());
-    wasValidated = false;
-  }
-  return wasValidated;
-}
-
-void
-NfdRibCommandProcessor::insertPrefix(const ndn::mgmt::ControlParameters& parameters)
-{
-  const ndn::nfd::ControlParameters& castParams =
-    static_cast<const ndn::nfd::ControlParameters&>(parameters);
-
-  _LOG_DEBUG("Inserting prefix into the FIB: " << castParams.getName() << "\n");
-
-  if (m_namePrefixList.insert(castParams.getName())) {
-    m_lsdb.buildAndInstallOwnNameLsa();
-  }
-}
-
-void
-NfdRibCommandProcessor::removePrefix(const ndn::mgmt::ControlParameters& parameters)
-{
-  const ndn::nfd::ControlParameters& castParams =
-    static_cast<const ndn::nfd::ControlParameters&>(parameters);
-
-  _LOG_DEBUG("Removing prefix from the FIB: " << castParams.getName() << "\n");
-
-  if (m_namePrefixList.remove(castParams.getName())) {
-    m_lsdb.buildAndInstallOwnNameLsa();
-  }
+  m_dispatcher.addControlCommand<ndn::nfd::ControlParameters>(makeRelPrefix("unregister"),
+    ndn::mgmt::makeAcceptAllAuthorization(),
+    std::bind(&NfdRibCommandProcessor::validateParameters<NfdRibUnregisterCommand>, this, _1),
+    bind(&NfdRibCommandProcessor::withdrawAndRemovePrefix, this, _1, _2, _3, _4));
 }
 
 } // namespace update
diff --git a/src/update/nfd-rib-command-processor.hpp b/src/update/nfd-rib-command-processor.hpp
index 239d349..4b6ca5c 100644
--- a/src/update/nfd-rib-command-processor.hpp
+++ b/src/update/nfd-rib-command-processor.hpp
@@ -22,98 +22,22 @@
 #ifndef UPDATE_NFD_RIB_COMMAND_PROCESSOR_HPP
 #define UPDATE_NFD_RIB_COMMAND_PROCESSOR_HPP
 
+#include "manager-base.hpp"
 #include "route/fib.hpp"
 #include "nfd-rib-commands.hpp"
-#include "name-prefix-list.hpp"
-#include "lsdb.hpp"
 
-#include <ndn-cxx/mgmt/nfd/control-command.hpp>
-#include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
-#include <ndn-cxx/mgmt/dispatcher.hpp>
 #include <ndn-cxx/encoding/tlv-nfd.hpp>
 
-#include <boost/noncopyable.hpp>
-#include <typeinfo>
 
 namespace nlsr {
 namespace update {
 
-class NfdRibCommandProcessor : boost::noncopyable
+class NfdRibCommandProcessor : public CommandManagerBase
 {
 public:
-  class Error : public std::runtime_error
-  {
-  public:
-    explicit
-    Error(const std::string& what)
-      : std::runtime_error(what)
-    {
-    }
-  };
-
-public:
   NfdRibCommandProcessor(ndn::mgmt::Dispatcher& dispatcher,
-                         NamePrefixList& namePrefixes,
+                         NamePrefixList& namePrefixList,
                          Lsdb& lsdb);
-
-  /*! \brief Registers an Interest filter with face
-
-    Registers with face an Interest filter that reacts to any
-    interests on COMMAND_PREFIX.
-   */
-  void
-  startListening();
-
-PUBLIC_WITH_TESTS_ELSE_PRIVATE:
-
-  /*! \brief inserts a prefix into the FIB if parameters is valid.
-
-    We consider parameters to be valid if origin is set to CLIENT and
-    a name is present.
-   */
-  void
-  insertPrefix(const ndn::mgmt::ControlParameters& parameters);
-
-  /*! \brief remove a prefix from the FIB if parameters is valid.
-
-    We consider parameters to be valid if origin is set to CLIENT and
-    a name is present.
-   */
-  void
-  removePrefix(const ndn::mgmt::ControlParameters& parameters);
-
-  /*! \brief uses command's validator to check that parameters is valid.
-
-    The command's validator's behavior is defined per command.
-   */
-  template<typename T>
-  bool
-  validateParameters(const ndn::mgmt::ControlParameters& parameters)
-  {
-    BOOST_ASSERT(dynamic_cast<const ndn::nfd::ControlParameters*>(&parameters) != nullptr);
-    const ndn::nfd::ControlParameters& castParams =
-      static_cast<const ndn::nfd::ControlParameters&>(parameters);
-    T command;
-    try {
-      command.validateRequest(castParams);
-    }
-    catch (const ndn::nfd::ControlCommand::ArgumentError& ae) {
-      throw ae;
-    }
-    catch (...) {
-      return false;
-    }
-    return true;
-  }
-
-private:
-  template<typename T>
-  bool
-  validate(const ndn::mgmt::ControlParameters& parameters, const ndn::PartialName& command);
-
-  ndn::mgmt::Dispatcher& m_dispatcher;
-  NamePrefixList& m_namePrefixList;
-  Lsdb& m_lsdb;
 };
 
 } // namespace update
diff --git a/src/update/prefix-update-processor.cpp b/src/update/prefix-update-processor.cpp
index ad1f9a6..6146441 100644
--- a/src/update/prefix-update-processor.cpp
+++ b/src/update/prefix-update-processor.cpp
@@ -20,60 +20,84 @@
  **/
 
 #include "prefix-update-processor.hpp"
-
 #include "lsdb.hpp"
 #include "nlsr.hpp"
-#include "prefix-update-commands.hpp"
-
 #include <ndn-cxx/mgmt/nfd/control-response.hpp>
+#include <ndn-cxx/tag.hpp>
+#include <ndn-cxx/util/io.hpp>
 
 namespace nlsr {
 namespace update {
 
 INIT_LOGGER("PrefixUpdateProcessor");
 
-const ndn::Name::Component PrefixUpdateProcessor::MODULE_COMPONENT = ndn::Name::Component("prefix-update");
-const ndn::Name::Component PrefixUpdateProcessor::ADVERTISE_VERB = ndn::Name::Component("advertise");
-const ndn::Name::Component PrefixUpdateProcessor::WITHDRAW_VERB  = ndn::Name::Component("withdraw");
+/** \brief an Interest tag to indicate command signer
+ */
+using SignerTag = ndn::SimpleTag<ndn::Name, 20>;
 
-PrefixUpdateProcessor::PrefixUpdateProcessor(ndn::Face& face,
+/** \brief obtain signer from SignerTag attached to Interest, if available
+ */
+static ndn::optional<std::string>
+getSignerFromTag(const ndn::Interest& interest)
+{
+  shared_ptr<SignerTag> signerTag = interest.getTag<SignerTag>();
+  if (signerTag == nullptr) {
+    return ndn::nullopt;
+  }
+  else {
+    return signerTag->get().toUri();
+  }
+}
+
+PrefixUpdateProcessor::PrefixUpdateProcessor(ndn::mgmt::Dispatcher& dispatcher,
+                                             ndn::Face& face,
                                              NamePrefixList& namePrefixList,
                                              Lsdb& lsdb,
                                              const ndn::Name broadcastPrefix,
                                              ndn::KeyChain& keyChain,
                                              std::shared_ptr<ndn::CertificateCacheTtl> certificateCache,
                                              security::CertificateStore& certStore)
-  : m_face(face)
-  , m_namePrefixList(namePrefixList)
-  , m_lsdb(lsdb)
-  , m_keyChain(keyChain)
-  , m_validator(m_face, broadcastPrefix, certificateCache, certStore)
-  , m_isEnabled(false)
-  , COMMAND_PREFIX(ndn::Name(Nlsr::LOCALHOST_PREFIX).append(MODULE_COMPONENT))
+  : CommandManagerBase(dispatcher, namePrefixList, lsdb, "prefix-update")
+  , m_validator(face, broadcastPrefix, certificateCache, certStore)
 {
+  _LOG_DEBUG("Setting dispatcher to capture Interests for: "
+    << ndn::Name(Nlsr::LOCALHOST_PREFIX).append("prefix-update"));
+
+  m_dispatcher.addControlCommand<ndn::nfd::ControlParameters>(makeRelPrefix("advertise"),
+    makeAuthorization(),
+    std::bind(&PrefixUpdateProcessor::validateParameters<AdvertisePrefixCommand>,
+                this, _1),
+    std::bind(&PrefixUpdateProcessor::advertiseAndInsertPrefix, this, _1, _2, _3, _4));
+
+  m_dispatcher.addControlCommand<ndn::nfd::ControlParameters>(makeRelPrefix("withdraw"),
+    makeAuthorization(),
+    std::bind(&PrefixUpdateProcessor::validateParameters<WithdrawPrefixCommand>,
+                this, _1),
+    std::bind(&PrefixUpdateProcessor::withdrawAndRemovePrefix, this, _1, _2, _3, _4));
 }
 
-void
-PrefixUpdateProcessor::startListening()
+ndn::mgmt::Authorization
+PrefixUpdateProcessor::makeAuthorization()
 {
-  _LOG_DEBUG("Setting Interest filter for: " << COMMAND_PREFIX);
+  return [=] (const ndn::Name& prefix, const ndn::Interest& interest,
+              const ndn::mgmt::ControlParameters* params,
+              const ndn::mgmt::AcceptContinuation& accept,
+              const ndn::mgmt::RejectContinuation& reject) {
+    m_validator.validate(interest,
+      [accept] (const std::shared_ptr<const ndn::Interest>& request) {
 
-  m_face.setInterestFilter(COMMAND_PREFIX, std::bind(&PrefixUpdateProcessor::onInterest, this, _2));
-}
-
-void
-PrefixUpdateProcessor::onInterest(const ndn::Interest& request)
-{
-  _LOG_TRACE("Received Interest: " << request);
-
-  if (!m_isEnabled) {
-    sendNack(request);
-    return;
-  }
-
-  m_validator.validate(request,
-                       std::bind(&PrefixUpdateProcessor::onCommandValidated, this, _1),
-                       std::bind(&PrefixUpdateProcessor::onCommandValidationFailed, this, _1, _2));
+        auto signer1 = getSignerFromTag(*request);
+        std::string signer = signer1.value_or("*");
+        _LOG_DEBUG("accept " << request->getName() << " signer=" << signer);
+        accept(signer);
+      },
+      [reject] (const std::shared_ptr<const ndn::Interest>& request,
+                const std::string& failureInfo) {
+        _LOG_DEBUG("reject " << request->getName() << " signer=" <<
+                      getSignerFromTag(*request).value_or("?") << ' ' << failureInfo);
+        reject(ndn::mgmt::RejectReply::STATUS403);
+      });
+  };
 }
 
 void
@@ -83,140 +107,5 @@
   m_validator.load(section, filename);
 }
 
-void
-PrefixUpdateProcessor::onCommandValidated(const std::shared_ptr<const ndn::Interest>& request)
-{
-  const ndn::Name& command = request->getName();
-  const ndn::Name::Component& verb = command[COMMAND_PREFIX.size()];
-  const ndn::Name::Component& parameterComponent = command[COMMAND_PREFIX.size() + 1];
-
-  if (verb == ADVERTISE_VERB || verb == WITHDRAW_VERB) {
-    ndn::nfd::ControlParameters parameters;
-
-    if (!extractParameters(parameterComponent, parameters)) {
-      sendResponse(request, 400, "Malformed command");
-      return;
-    }
-
-    if (verb == ADVERTISE_VERB) {
-      advertise(request, parameters);
-    }
-    else if (verb == WITHDRAW_VERB) {
-      withdraw(request, parameters);
-    }
-
-    sendResponse(request, 200, "Success");
-  }
-  else {
-    sendResponse(request, 501, "Unsupported command");
-  }
-}
-
-void
-PrefixUpdateProcessor::onCommandValidationFailed(const std::shared_ptr<const ndn::Interest>& request,
-                                                 const std::string& failureInfo)
-{
-  sendResponse(request, 403, failureInfo);
-}
-
-bool
-PrefixUpdateProcessor::extractParameters(const ndn::Name::Component& parameterComponent,
-                                         ndn::nfd::ControlParameters& extractedParameters)
-{
-  try {
-    ndn::Block rawParameters = parameterComponent.blockFromValue();
-    extractedParameters.wireDecode(rawParameters);
-  }
-  catch (const ndn::tlv::Error&) {
-    return false;
-  }
-
-  return true;
-}
-
-void
-PrefixUpdateProcessor::advertise(const std::shared_ptr<const ndn::Interest>& request,
-                                 const ndn::nfd::ControlParameters& parameters)
-{
-  AdvertisePrefixCommand command;
-
-  if (!validateParameters(command, parameters)) {
-    sendResponse(request, 400, "Malformed command");
-    return;
-  }
-
-  _LOG_INFO("Advertising name: " << parameters.getName());
-
-  if (m_namePrefixList.insert(parameters.getName())) {
-    // Only build a Name LSA if the added name is new
-    m_lsdb.buildAndInstallOwnNameLsa();
-  }
-}
-
-void
-PrefixUpdateProcessor::withdraw(const std::shared_ptr<const ndn::Interest>& request,
-                                const ndn::nfd::ControlParameters& parameters)
-{
-  WithdrawPrefixCommand command;
-
-  if (!validateParameters(command, parameters)) {
-    sendResponse(request, 400, "Malformed command");
-    return;
-  }
-
-  _LOG_INFO("Withdrawing name: " << parameters.getName());
-
-  if (m_namePrefixList.remove(parameters.getName())) {
-    // Only build a Name LSA if a name was actually removed
-    m_lsdb.buildAndInstallOwnNameLsa();
-  }
-}
-
-bool
-PrefixUpdateProcessor::validateParameters(const ndn::nfd::ControlCommand& command,
-                                          const ndn::nfd::ControlParameters& parameters)
-{
-  try {
-    command.validateRequest(parameters);
-  }
-  catch (const ndn::nfd::ControlCommand::ArgumentError&) {
-    return false;
-  }
-
-  return true;
-}
-
-void
-PrefixUpdateProcessor::sendNack(const ndn::Interest& request)
-{
-  ndn::MetaInfo metaInfo;
-  metaInfo.setType(ndn::tlv::ContentType_Nack);
-
-  std::shared_ptr<ndn::Data> responseData = std::make_shared<ndn::Data>(request.getName());
-  responseData->setMetaInfo(metaInfo);
-
-  m_keyChain.sign(*responseData);
-  m_face.put(*responseData);
-}
-
-void
-PrefixUpdateProcessor::sendResponse(const std::shared_ptr<const ndn::Interest>& request,
-                                    uint32_t code,
-                                    const std::string& text)
-{
-  if (request == nullptr) {
-    return;
-  }
-
-  ndn::nfd::ControlResponse response(code, text);
-  const ndn::Block& encodedControl = response.wireEncode();
-
-  std::shared_ptr<ndn::Data> responseData = std::make_shared<ndn::Data>(request->getName());
-  responseData->setContent(encodedControl);
-
-  m_keyChain.sign(*responseData);
-  m_face.put(*responseData);
-}
-
 } // namespace update
 } // namespace nlsr
diff --git a/src/update/prefix-update-processor.hpp b/src/update/prefix-update-processor.hpp
index f1a5b50..6ee9506 100644
--- a/src/update/prefix-update-processor.hpp
+++ b/src/update/prefix-update-processor.hpp
@@ -22,24 +22,20 @@
 #ifndef NLSR_UPDATE_PREFIX_UPDATE_PROCESSOR_HPP
 #define NLSR_UPDATE_PREFIX_UPDATE_PROCESSOR_HPP
 
-#include "name-prefix-list.hpp"
+#include "manager-base.hpp"
+#include "prefix-update-commands.hpp"
 #include "test-access-control.hpp"
 #include "validator.hpp"
 
-#include <ndn-cxx/face.hpp>
-#include <ndn-cxx/interest.hpp>
-#include <ndn-cxx/mgmt/nfd/control-command.hpp>
-#include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
 #include <ndn-cxx/security/certificate-cache-ttl.hpp>
 #include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/security/v2/validator.hpp>
 
-#include <boost/noncopyable.hpp>
 #include <boost/property_tree/ptree.hpp>
+#include <memory>
 
 namespace nlsr {
 
-class Lsdb;
-
 namespace security {
   class CertificateStore;
 } // namespace security
@@ -48,79 +44,20 @@
 
 typedef boost::property_tree::ptree ConfigSection;
 
-class PrefixUpdateProcessor : boost::noncopyable
+class PrefixUpdateProcessor : public CommandManagerBase
 {
 public:
-  class Error : public std::runtime_error
-  {
-  public:
-    explicit
-    Error(const std::string& what)
-      : std::runtime_error(what)
-    {
-    }
-  };
-
-public:
-  PrefixUpdateProcessor(ndn::Face& face,
+  PrefixUpdateProcessor(ndn::mgmt::Dispatcher& dispatcher,
+                        ndn::Face& face,
                         NamePrefixList& namePrefixList,
                         Lsdb& lsdb,
                         const ndn::Name broadcastPrefix,
                         ndn::KeyChain& keyChain,
                         std::shared_ptr<ndn::CertificateCacheTtl> certificateCache,
                         security::CertificateStore& certStore);
-
   void
   loadValidator(ConfigSection section, const std::string& filename);
 
-  void
-  startListening();
-
-  void
-  enable()
-  {
-    m_isEnabled = true;
-  }
-
-private:
-  void
-  onInterest(const ndn::Interest& request);
-
-  void
-  sendNack(const ndn::Interest& request);
-
-  void
-  sendResponse(const std::shared_ptr<const ndn::Interest>& request,
-               uint32_t code,
-               const std::string& text);
-
-  /*! \brief adds desired name prefix to the advertised name prefix list
-   */
-  void
-  advertise(const std::shared_ptr<const ndn::Interest>& request,
-            const ndn::nfd::ControlParameters& parameters);
-
-  /*! \brief removes desired name prefix from the advertised name prefix list
-   */
-  void
-  withdraw(const std::shared_ptr<const ndn::Interest>& request,
-           const ndn::nfd::ControlParameters& parameters);
-
-  void
-  onCommandValidated(const std::shared_ptr<const ndn::Interest>& request);
-
-  void
-  onCommandValidationFailed(const std::shared_ptr<const ndn::Interest>& request,
-                            const std::string& failureInfo);
-
-  static bool
-  extractParameters(const ndn::name::Component& parameterComponent,
-                    ndn::nfd::ControlParameters& extractedParameters);
-
-  bool
-  validateParameters(const ndn::nfd::ControlCommand& command,
-                     const ndn::nfd::ControlParameters& parameters);
-
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   Validator&
   getValidator()
@@ -129,18 +66,17 @@
   }
 
 private:
-  ndn::Face& m_face;
-  NamePrefixList& m_namePrefixList;
-  Lsdb& m_lsdb;
-  ndn::KeyChain& m_keyChain;
+  /*! \brief an authorization function for prefix-update module and verb(advertise/withdraw)
+   *  accept if the verb is advertise/withdraw
+   *  reject if the verb is not advertise/withdraw
+      \retval an Authorization function
+      \sa Nlsr::getDispatcher()
+   */
+  ndn::mgmt::Authorization
+  makeAuthorization();
+
+private:
   Validator m_validator;
-  bool m_isEnabled;
-
-  const ndn::Name COMMAND_PREFIX; // /localhost/nlsr/prefix-update
-
-  static const ndn::Name::Component MODULE_COMPONENT;
-  static const ndn::Name::Component ADVERTISE_VERB;
-  static const ndn::Name::Component WITHDRAW_VERB;
 };
 
 } // namespace update