Use ndn::mgmt::Dispatcher for repo commands

refs #4129

Change-Id: Idb7826fc76b6660ce76d69e7e88a9e922c55a2e1
diff --git a/src/common.hpp b/src/common.hpp
index 0ccc485..bea3ddb 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017, Regents of the University of California.
+ * Copyright (c) 2014-2018, Regents of the University of California.
  *
  * This file is part of NDN repo-ng (Next generation of NDN repository).
  * See AUTHORS.md for complete list of repo-ng authors and contributors.
diff --git a/src/handles/base-handle.cpp b/src/handles/base-handle.cpp
deleted file mode 100644
index 8555f39..0000000
--- a/src/handles/base-handle.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2014-2017, Regents of the University of California.
- *
- * This file is part of NDN repo-ng (Next generation of NDN repository).
- * See AUTHORS.md for complete list of repo-ng authors and contributors.
- *
- * repo-ng 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.
- *
- * repo-ng 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
- * repo-ng, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "base-handle.hpp"
-
-#include <ndn-cxx/util/random.hpp>
-
-namespace repo {
-
-uint64_t
-BaseHandle::generateProcessId()
-{
-  return ndn::random::generateWord64();
-}
-
-} // namespace repo
diff --git a/src/handles/base-handle.hpp b/src/handles/base-handle.hpp
deleted file mode 100644
index 5d12076..0000000
--- a/src/handles/base-handle.hpp
+++ /dev/null
@@ -1,132 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2017, Regents of the University of California.
- *
- * This file is part of NDN repo-ng (Next generation of NDN repository).
- * See AUTHORS.md for complete list of repo-ng authors and contributors.
- *
- * repo-ng 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.
- *
- * repo-ng 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
- * repo-ng, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef REPO_HANDLES_BASE_HANDLE_HPP
-#define REPO_HANDLES_BASE_HANDLE_HPP
-
-#include "common.hpp"
-
-#include "storage/repo-storage.hpp"
-#include "repo-command-response.hpp"
-#include "repo-command-parameter.hpp"
-
-namespace repo {
-
-class BaseHandle : noncopyable
-{
-public:
-  class Error : public std::runtime_error
-  {
-  public:
-    explicit
-    Error(const std::string& what)
-      : std::runtime_error(what)
-    {
-    }
-  };
-
-public:
-  BaseHandle(Face& face, RepoStorage& storageHandle, KeyChain& keyChain,
-             Scheduler& scheduler)
-    : m_storageHandle(storageHandle)
-    , m_face(face)
-    , m_keyChain(keyChain)
-    , m_scheduler(scheduler)
-   // , m_storeindex(storeindex)
-  {
-  }
-
-  virtual
-  ~BaseHandle() = default;
-
-  virtual void
-  listen(const Name& prefix) = 0;
-
-protected:
-
-  inline Face&
-  getFace()
-  {
-    return m_face;
-  }
-
-  inline RepoStorage&
-  getStorageHandle()
-  {
-    return m_storageHandle;
-  }
-
-  inline Scheduler&
-  getScheduler()
-  {
-    return m_scheduler;
-  }
-
-  // inline RepoStorage&
-  // getStoreIndex()
-  // {
-  //   return m_storeindex;
-  // }
-
-  uint64_t
-  generateProcessId();
-
-  void
-  reply(const Interest& commandInterest, const RepoCommandResponse& response);
-
-
-  /**
-   * @brief extract RepoCommandParameter from a command Interest.
-   * @param interest command Interest
-   * @param prefix Name prefix up to command-verb
-   * @param[out] parameter parsed parameter
-   * @throw RepoCommandParameter::Error parse error
-   */
-  void
-  extractParameter(const Interest& interest, const Name& prefix, RepoCommandParameter& parameter);
-
-protected:
-  RepoStorage& m_storageHandle;
-
-private:
-  Face& m_face;
-  KeyChain& m_keyChain;
-  Scheduler& m_scheduler;
- // RepoStorage& m_storeindex;
-};
-
-inline void
-BaseHandle::reply(const Interest& commandInterest, const RepoCommandResponse& response)
-{
-  std::shared_ptr<Data> rdata = std::make_shared<Data>(commandInterest.getName());
-  rdata->setContent(response.wireEncode());
-  m_keyChain.sign(*rdata);
-  m_face.put(*rdata);
-}
-
-inline void
-BaseHandle::extractParameter(const Interest& interest, const Name& prefix,
-                             RepoCommandParameter& parameter)
-{
-  parameter.wireDecode(interest.getName().get(prefix.size()).blockFromValue());
-}
-
-} // namespace repo
-
-#endif // REPO_HANDLES_BASE_HANDLE_HPP
diff --git a/src/handles/command-base-handle.cpp b/src/handles/command-base-handle.cpp
new file mode 100644
index 0000000..1717839
--- /dev/null
+++ b/src/handles/command-base-handle.cpp
@@ -0,0 +1,77 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2018, Regents of the University of California.
+ *
+ * This file is part of NDN repo-ng (Next generation of NDN repository).
+ * See AUTHORS.md for complete list of repo-ng authors and contributors.
+ *
+ * repo-ng 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.
+ *
+ * repo-ng 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
+ * repo-ng, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "command-base-handle.hpp"
+
+#include <ndn-cxx/util/random.hpp>
+
+namespace repo {
+
+/** \brief an Interest tag to indicate command signer
+ */
+using SignerTag = ndn::SimpleTag<ndn::Name, 20>;
+
+/** \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();
+  }
+}
+
+CommandBaseHandle::CommandBaseHandle(Face& face, RepoStorage& storageHandle,
+                  Scheduler& scheduler, Validator& validator)
+  : face(face)
+  , storageHandle(storageHandle)
+  , scheduler(scheduler)
+  , m_validator(validator)
+{
+}
+
+ndn::mgmt::Authorization
+CommandBaseHandle::makeAuthorization()
+{
+  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 ndn::Interest& request) {
+
+      auto signer1 = getSignerFromTag(request);
+      std::string signer = signer1.value_or("*");
+      //_LOG_DEBUG("accept " << request->getName() << " signer=" << signer);
+      accept(signer);
+    },
+    [reject] (const ndn::Interest& request,
+              const ndn::security::v2::ValidationError& error) {
+      //_LOG_DEBUG("reject " << request->getName() << " signer=" <<
+      //              getSignerFromTag(*request).value_or("?") << ' ' << failureInfo);
+      reject(ndn::mgmt::RejectReply::STATUS403);
+    });
+  };
+}
+
+} // namespace repo
diff --git a/src/handles/command-base-handle.hpp b/src/handles/command-base-handle.hpp
new file mode 100644
index 0000000..205b884
--- /dev/null
+++ b/src/handles/command-base-handle.hpp
@@ -0,0 +1,84 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2018, Regents of the University of California.
+ *
+ * This file is part of NDN repo-ng (Next generation of NDN repository).
+ * See AUTHORS.md for complete list of repo-ng authors and contributors.
+ *
+ * repo-ng 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.
+ *
+ * repo-ng 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
+ * repo-ng, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef REPO_HANDLES_COMMAND_BASE_HANDLE_HPP
+#define REPO_HANDLES_COMMAND_BASE_HANDLE_HPP
+
+#include "common.hpp"
+
+#include "storage/repo-storage.hpp"
+#include "repo-command-response.hpp"
+#include "repo-command-parameter.hpp"
+#include "repo-command.hpp"
+
+#include <ndn-cxx/mgmt/dispatcher.hpp>
+
+namespace repo {
+
+class CommandBaseHandle
+{
+public:
+  class Error : public std::runtime_error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : std::runtime_error(what)
+    {
+    }
+  };
+
+public:
+  CommandBaseHandle(Face& face, RepoStorage& storageHandle,
+                    Scheduler& scheduler, Validator& validator);
+
+  virtual
+  ~CommandBaseHandle() = default;
+
+  ndn::mgmt::Authorization
+  makeAuthorization();
+
+  template<typename T>
+  bool
+  validateParameters(const ndn::mgmt::ControlParameters& parameters)
+  {
+    const RepoCommandParameter* castParams =
+      dynamic_cast<const RepoCommandParameter*>(&parameters);
+    BOOST_ASSERT(castParams != nullptr);
+    T command;
+    try {
+      command.validateRequest(*castParams);
+    }
+    catch (const RepoCommand::ArgumentError& ae) {
+      return false;
+    }
+    return true;
+  }
+
+protected:
+  Face& face;
+  RepoStorage& storageHandle;
+  Scheduler& scheduler;
+
+private:
+  Validator& m_validator;
+};
+} // namespace repo
+
+#endif // REPO_HANDLES_COMMAND_BASE_HANDLE_HPP
\ No newline at end of file
diff --git a/src/handles/delete-handle.cpp b/src/handles/delete-handle.cpp
index 17882bb..dc0f5f1 100644
--- a/src/handles/delete-handle.cpp
+++ b/src/handles/delete-handle.cpp
@@ -21,151 +21,112 @@
 
 namespace repo {
 
-DeleteHandle::DeleteHandle(Face& face, RepoStorage& storageHandle, KeyChain& keyChain,
-                           Scheduler& scheduler,
+DeleteHandle::DeleteHandle(Face& face, RepoStorage& storageHandle,
+                           ndn::mgmt::Dispatcher& dispatcher, Scheduler& scheduler,
                            Validator& validator)
-  : BaseHandle(face, storageHandle, keyChain, scheduler)
-  , m_validator(validator)
+  : CommandBaseHandle(face, storageHandle, scheduler, validator)
 {
+  dispatcher.addControlCommand<RepoCommandParameter>(ndn::PartialName("delete"),
+    makeAuthorization(),
+    std::bind(&DeleteHandle::validateParameters<DeleteCommand>, this, _1),
+    std::bind(&DeleteHandle::handleDeleteCommand, this, _1, _2, _3, _4));
+
 }
 
 void
-DeleteHandle::onInterest(const Name& prefix, const Interest& interest)
+DeleteHandle::handleDeleteCommand(const Name& prefix, const Interest& interest,
+                                  const ndn::mgmt::ControlParameters& parameter,
+                                  const ndn::mgmt::CommandContinuation& done)
 {
-  m_validator.validate(interest, bind(&DeleteHandle::onValidated, this, _1, prefix),
-                                 bind(&DeleteHandle::onValidationFailed, this, _1, _2));
-}
+  const RepoCommandParameter& repoParameter = dynamic_cast<const RepoCommandParameter&>(parameter);
 
-void
-DeleteHandle::onValidated(const Interest& interest, const Name& prefix)
-{
-  RepoCommandParameter parameter;
-
-  try {
-    extractParameter(interest, prefix, parameter);
-  }
-  catch (const RepoCommandParameter::Error&) {
-    negativeReply(interest, 403);
-    return;
-  }
-
-  if (parameter.hasSelectors()) {
-
-    if (parameter.hasStartBlockId() || parameter.hasEndBlockId()) {
-      negativeReply(interest, 402);
-      return;
-    }
-
+  if (repoParameter.hasSelectors()) {
     //choose data with selector and delete it
-    processSelectorDeleteCommand(interest, parameter);
+    processSelectorDeleteCommand(interest, repoParameter, done);
     return;
   }
 
-  if (!parameter.hasStartBlockId() && !parameter.hasEndBlockId()) {
-    processSingleDeleteCommand(interest, parameter);
+  if (!repoParameter.hasStartBlockId() && !repoParameter.hasEndBlockId()) {
+    processSingleDeleteCommand(interest, repoParameter, done);
     return;
   }
 
-  processSegmentDeleteCommand(interest, parameter);
+  processSegmentDeleteCommand(interest, repoParameter, done);
 }
 
-void
-DeleteHandle::onValidationFailed(const Interest& interest, const ValidationError& error)
-{
-  std::cerr << error << std::endl;
-  negativeReply(interest, 401);
-}
-//listen change the setinterestfilter
-void
-DeleteHandle::listen(const Name& prefix)
-{
-  getFace().setInterestFilter(Name(prefix).append("delete"),
-                              bind(&DeleteHandle::onInterest, this, _1, _2));
-}
-
-void
+RepoCommandResponse
 DeleteHandle::positiveReply(const Interest& interest, const RepoCommandParameter& parameter,
-                            uint64_t statusCode, uint64_t nDeletedDatas)
+                            uint64_t statusCode, uint64_t nDeletedData) const
 {
-  RepoCommandResponse response;
+  RepoCommandResponse response(statusCode, "Deletion Successful");
+
   if (parameter.hasProcessId()) {
     response.setProcessId(parameter.getProcessId());
-    response.setStatusCode(statusCode);
-    response.setDeleteNum(nDeletedDatas);
+    response.setDeleteNum(nDeletedData);
+    response.setBody(response.wireEncode());
   }
   else {
-    response.setStatusCode(403);
+    response.setCode(403);
+    response.setText("Malformed Command");
+    response.setBody(response.wireEncode());
   }
-  reply(interest, response);
+  return response;
+}
+
+RepoCommandResponse
+DeleteHandle::negativeReply(const Interest& interest, uint64_t statusCode, std::string text) const
+{
+  RepoCommandResponse response(statusCode, text);
+  response.setBody(response.wireEncode());
+  return response;
 }
 
 void
-DeleteHandle::negativeReply(const Interest& interest, uint64_t statusCode)
+DeleteHandle::processSingleDeleteCommand(const Interest& interest, const RepoCommandParameter& parameter,
+                                         const ndn::mgmt::CommandContinuation& done) const
 {
-  RepoCommandResponse response;
-  response.setStatusCode(statusCode);
-  reply(interest, response);
-}
-
-void
-DeleteHandle::processSingleDeleteCommand(const Interest& interest,
-                                         RepoCommandParameter& parameter)
-{
-  int64_t nDeletedDatas = getStorageHandle().deleteData(parameter.getName());
-  if (nDeletedDatas == -1) {
+  int64_t nDeletedData = storageHandle.deleteData(parameter.getName());
+  if (nDeletedData == -1) {
     std::cerr << "Deletion Failed!" <<std::endl;
-    negativeReply(interest, 405); //405 means deletion fail
+    done(negativeReply(interest, 405, "Deletion Failed"));
   }
   else
-    positiveReply(interest, parameter, 200, nDeletedDatas);
+  done(positiveReply(interest, parameter, 200, nDeletedData));
 }
 
 void
-DeleteHandle::processSelectorDeleteCommand(const Interest& interest,
-                                           RepoCommandParameter& parameter)
+DeleteHandle::processSelectorDeleteCommand(const Interest& interest, const RepoCommandParameter& parameter,
+                                           const ndn::mgmt::CommandContinuation& done) const
 {
-  int64_t nDeletedDatas = getStorageHandle()
-                            .deleteData(Interest(parameter.getName())
-                                          .setSelectors(parameter.getSelectors()));
-  if (nDeletedDatas == -1) {
+  int64_t nDeletedData = storageHandle.deleteData(Interest(parameter.getName())
+                                      .setSelectors(parameter.getSelectors()));
+  if (nDeletedData == -1) {
     std::cerr << "Deletion Failed!" <<std::endl;
-    negativeReply(interest, 405); //405 means deletion fail
+    done(negativeReply(interest, 405, "Deletion Failed"));
   }
   else
-    positiveReply(interest, parameter, 200, nDeletedDatas);
+    done(positiveReply(interest, parameter, 200, nDeletedData));
 }
 
 void
-DeleteHandle::processSegmentDeleteCommand(const Interest& interest,
-                                          RepoCommandParameter& parameter)
+DeleteHandle::processSegmentDeleteCommand(const Interest& interest, const RepoCommandParameter& parameter,
+                                          const ndn::mgmt::CommandContinuation& done) const
 {
-  if (!parameter.hasStartBlockId())
-    parameter.setStartBlockId(0);
+  SegmentNo startBlockId = parameter.hasStartBlockId() ? parameter.getStartBlockId() : 0;
+  SegmentNo endBlockId = parameter.getEndBlockId();
 
-  if (parameter.hasEndBlockId()) {
-    SegmentNo startBlockId = parameter.getStartBlockId();
-    SegmentNo endBlockId = parameter.getEndBlockId();
-
-    if (startBlockId > endBlockId) {
-      negativeReply(interest, 403);
-      return;
+  Name prefix = parameter.getName();
+  uint64_t nDeletedData = 0;
+  for (SegmentNo i = startBlockId; i <= endBlockId; i++) {
+    Name name = prefix;
+    name.appendSegment(i);
+    if (storageHandle.deleteData(name)) {
+      nDeletedData++;
     }
+  }
+  //All the data deleted, return 200
+  done(positiveReply(interest, parameter, 200, nDeletedData));
 
-    Name prefix = parameter.getName();
-    uint64_t nDeletedDatas = 0;
-    for (SegmentNo i = startBlockId; i <= endBlockId; i++) {
-      Name name = prefix;
-      name.appendSegment(i);
-      if (getStorageHandle().deleteData(name)) {
-        nDeletedDatas++;
-      }
-    }
-    //All the data deleted, return 200
-    positiveReply(interest, parameter, 200, nDeletedDatas);
-  }
-  else {
-    BOOST_ASSERT(false); // segmented deletion without EndBlockId, not implemented
-  }
 }
 
 } // namespace repo
diff --git a/src/handles/delete-handle.hpp b/src/handles/delete-handle.hpp
index 17cb48a..fbb25d3 100644
--- a/src/handles/delete-handle.hpp
+++ b/src/handles/delete-handle.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017, Regents of the University of California.
+ * Copyright (c) 2014-2018, Regents of the University of California.
  *
  * This file is part of NDN repo-ng (Next generation of NDN repository).
  * See AUTHORS.md for complete list of repo-ng authors and contributors.
@@ -20,66 +20,54 @@
 #ifndef REPO_HANDLES_DELETE_HANDLE_HPP
 #define REPO_HANDLES_DELETE_HANDLE_HPP
 
-#include "base-handle.hpp"
+#include "command-base-handle.hpp"
+
+#include <ndn-cxx/mgmt/dispatcher.hpp>
 
 namespace repo {
 
-class DeleteHandle : public BaseHandle
+class DeleteHandle : public CommandBaseHandle
 {
 
 public:
-  class Error : public BaseHandle::Error
+  class Error : public CommandBaseHandle::Error
   {
   public:
     explicit
     Error(const std::string& what)
-      : BaseHandle::Error(what)
+      : CommandBaseHandle::Error(what)
     {
     }
   };
 
 public:
-  DeleteHandle(Face& face, RepoStorage& storageHandle, KeyChain& keyChain,
-               Scheduler& scheduler, Validator& validator);
-
-  virtual void
-  listen(const Name& prefix);
+  DeleteHandle(Face& face, RepoStorage& storageHandle,
+               ndn::mgmt::Dispatcher& dispatcher, Scheduler& scheduler, Validator& validator);
 
 private:
   void
-  onInterest(const Name& prefix, const Interest& interest);
+  handleDeleteCommand(const Name& prefix, const Interest& interest,
+                      const ndn::mgmt::ControlParameters& parameters,
+                      const ndn::mgmt::CommandContinuation& done);
 
-  void
-  onValidated(const Interest& interest, const Name& prefix);
-
-  void
-  onValidationFailed(const Interest& interest, const ValidationError& error);
-
-  /**
-   * @todo delete check has not been realized due to the while loop of segmented data deletion.
-   */
-  void
-  onCheckInterest(const Name& prefix, const Interest& interest);
-
-  void
+  RepoCommandResponse
   positiveReply(const Interest& interest, const RepoCommandParameter& parameter,
-                uint64_t statusCode, uint64_t nDeletedDatas);
+                uint64_t statusCode, uint64_t nDeletedData) const;
+
+  RepoCommandResponse
+  negativeReply(const Interest& interest, uint64_t statusCode, const std::string text) const;
 
   void
-  negativeReply(const Interest& interest, uint64_t statusCode);
+  processSingleDeleteCommand(const Interest& interest, const RepoCommandParameter& parameter,
+                             const ndn::mgmt::CommandContinuation& done) const;
 
   void
-  processSingleDeleteCommand(const Interest& interest, RepoCommandParameter& parameter);
+  processSelectorDeleteCommand(const Interest& interest, const RepoCommandParameter& parameter,
+                               const ndn::mgmt::CommandContinuation& done) const;
 
   void
-  processSelectorDeleteCommand(const Interest& interest, RepoCommandParameter& parameter);
-
-  void
-  processSegmentDeleteCommand(const Interest& interest, RepoCommandParameter& parameter);
-
-private:
-  Validator& m_validator;
-
+  processSegmentDeleteCommand(const Interest& interest, const RepoCommandParameter& parameter,
+                              const ndn::mgmt::CommandContinuation& done) const;
 };
 
 } // namespace repo
diff --git a/src/handles/read-handle.cpp b/src/handles/read-handle.cpp
index b880bdd..44a9d18 100644
--- a/src/handles/read-handle.cpp
+++ b/src/handles/read-handle.cpp
@@ -22,10 +22,10 @@
 
 namespace repo {
 
-ReadHandle::ReadHandle(Face& face, RepoStorage& storageHandle, KeyChain& keyChain,
-                       Scheduler& scheduler, size_t prefixSubsetLength)
-  : BaseHandle(face, storageHandle, keyChain, scheduler)
-  , m_prefixSubsetLength(prefixSubsetLength)
+ReadHandle::ReadHandle(Face& face, RepoStorage& storageHandle, size_t prefixSubsetLength)
+  : m_prefixSubsetLength(prefixSubsetLength)
+  , m_face(face)
+  , m_storageHandle(storageHandle)
 {
   connectAutoListen();
 }
@@ -49,9 +49,9 @@
 void
 ReadHandle::onInterest(const Name& prefix, const Interest& interest)
 {
-  shared_ptr<ndn::Data> data = getStorageHandle().readData(interest);
+  shared_ptr<ndn::Data> data = m_storageHandle.readData(interest);
   if (data != nullptr) {
-      getFace().put(*data);
+      m_face.put(*data);
   }
 }
 
@@ -59,14 +59,14 @@
 ReadHandle::onRegisterFailed(const Name& prefix, const std::string& reason)
 {
   std::cerr << "ERROR: Failed to register prefix in local hub's daemon" << std::endl;
-  getFace().shutdown();
+  m_face.shutdown();
 }
 
 void
 ReadHandle::listen(const Name& prefix)
 {
   ndn::InterestFilter filter(prefix);
-  getFace().setInterestFilter(filter,
+  m_face.setInterestFilter(filter,
                               bind(&ReadHandle::onInterest, this, _1, _2),
                               bind(&ReadHandle::onRegisterFailed, this, _1, _2));
 }
@@ -80,7 +80,7 @@
   auto check = m_insertedDataPrefixes.find(prefix);
   if (check != m_insertedDataPrefixes.end()) {
     if (--(check->second.useCount) <= 0) {
-      getFace().unsetInterestFilter(check->second.prefixId);
+      m_face.unsetInterestFilter(check->second.prefixId);
       m_insertedDataPrefixes.erase(prefix);
     }
   }
@@ -101,7 +101,7 @@
     // everything down, anyway. If registration failures are ever
     // considered to be recoverable, we would need to make this
     // atomic.
-    const ndn::RegisteredPrefixId* prefixId = getFace().setInterestFilter(filter,
+    const ndn::RegisteredPrefixId* prefixId = m_face.setInterestFilter(filter,
       [this] (const ndn::InterestFilter& filter, const Interest& interest) {
         // Implicit conversion to Name of filter
         onInterest(filter, interest);
diff --git a/src/handles/read-handle.hpp b/src/handles/read-handle.hpp
index 8ec67a2..a243abd 100644
--- a/src/handles/read-handle.hpp
+++ b/src/handles/read-handle.hpp
@@ -21,11 +21,15 @@
 #define REPO_HANDLES_READ_HANDLE_HPP
 
 #include "common.hpp"
-#include "base-handle.hpp"
+
+#include "storage/repo-storage.hpp"
+#include "repo-command-response.hpp"
+#include "repo-command-parameter.hpp"
+#include "repo-command.hpp"
 
 namespace repo {
 
-class ReadHandle : public BaseHandle
+class ReadHandle : public noncopyable
 {
 
 public:
@@ -37,11 +41,10 @@
     int useCount;
   };
 
-  ReadHandle(Face& face, RepoStorage& storageHandle, KeyChain& keyChain,
-             Scheduler& scheduler, size_t prefixSubsetLength);
+  ReadHandle(Face& face, RepoStorage& storageHandle, size_t prefixSubsetLength);
 
   void
-  listen(const Name& prefix) override;
+  listen(const Name& prefix);
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   const std::map<ndn::Name, RegisteredDataPrefix>&
@@ -80,6 +83,8 @@
   std::map<ndn::Name, RegisteredDataPrefix> m_insertedDataPrefixes;
   ndn::util::signal::ScopedConnection afterDataDeletionConnection;
   ndn::util::signal::ScopedConnection afterDataInsertionConnection;
+  Face& m_face;
+  RepoStorage& m_storageHandle;
 };
 
 } // namespace repo
diff --git a/src/handles/watch-handle.cpp b/src/handles/watch-handle.cpp
index 6fe93d4..105e802 100644
--- a/src/handles/watch-handle.cpp
+++ b/src/handles/watch-handle.cpp
@@ -21,12 +21,12 @@
 
 namespace repo {
 
-static const milliseconds PROCESS_DELETE_TIME(10000);
-static const milliseconds DEFAULT_INTEREST_LIFETIME(4000);
+static const milliseconds PROCESS_DELETE_TIME(10000_ms);
+static const milliseconds DEFAULT_INTEREST_LIFETIME(4000_ms);
 
-WatchHandle::WatchHandle(Face& face, RepoStorage& storageHandle, KeyChain& keyChain,
-                         Scheduler& scheduler, Validator& validator)
-  : BaseHandle(face, storageHandle, keyChain, scheduler)
+WatchHandle::WatchHandle(Face& face, RepoStorage& storageHandle,
+                         ndn::mgmt::Dispatcher& dispatcher, Scheduler& scheduler, Validator& validator)
+  : CommandBaseHandle(face, storageHandle, scheduler, validator)
   , m_validator(validator)
   , m_interestNum(0)
   , m_maxInterestNum(0)
@@ -35,6 +35,20 @@
   , m_startTime(steady_clock::now())
   , m_size(0)
 {
+  dispatcher.addControlCommand<RepoCommandParameter>(ndn::PartialName("watch").append("start"),
+    makeAuthorization(),
+    std::bind(&WatchHandle::validateParameters<WatchStartCommand>, this, _1),
+    std::bind(&WatchHandle::handleStartCommand, this, _1, _2, _3, _4));
+
+  dispatcher.addControlCommand<RepoCommandParameter>(ndn::PartialName("watch").append("check"),
+    makeAuthorization(),
+    std::bind(&WatchHandle::validateParameters<WatchCheckCommand>, this, _1),
+    std::bind(&WatchHandle::handleCheckCommand, this, _1, _2, _3, _4));
+
+  dispatcher.addControlCommand<RepoCommandParameter>(ndn::PartialName("watch").append("stop"),
+    makeAuthorization(),
+    std::bind(&WatchHandle::validateParameters<WatchStopCommand>, this, _1),
+    std::bind(&WatchHandle::handleStopCommand, this, _1, _2, _3, _4));
 }
 
 void
@@ -43,28 +57,13 @@
   m_processes.erase(name);
 }
 
-// Interest.
 void
-WatchHandle::onInterest(const Name& prefix, const Interest& interest)
+WatchHandle::handleStartCommand(const Name& prefix, const Interest& interest,
+                                const ndn::mgmt::ControlParameters& parameter,
+                                const ndn::mgmt::CommandContinuation& done)
 {
-  m_validator.validate(interest,
-                       bind(&WatchHandle::onValidated, this, _1, prefix),
-                       bind(&WatchHandle::onValidationFailed, this, _1, _2));
-}
-
-void
-WatchHandle::onValidated(const Interest& interest, const Name& prefix)
-{
-  RepoCommandParameter parameter;
-  try {
-    extractParameter(interest, prefix, parameter);
-  }
-  catch (const RepoCommandParameter::Error&) {
-    negativeReply(interest, 403);
-    return;
-  }
-
-  processWatchCommand(interest, parameter);
+  const RepoCommandParameter& repoParameter = dynamic_cast<const RepoCommandParameter&>(parameter);
+  processWatchCommand(interest, repoParameter, done);
 }
 
 void WatchHandle::watchStop(const Name& name)
@@ -73,24 +72,18 @@
   m_maxInterestNum = 0;
   m_interestNum = 0;
   m_startTime = steady_clock::now();
-  m_watchTimeout = milliseconds(0);
+  m_watchTimeout = 0_ms;
   m_interestLifetime = DEFAULT_INTEREST_LIFETIME;
   m_size = 0;
 }
 
-void
-WatchHandle::onValidationFailed(const Interest& interest, const ValidationError& error)
-{
-  std::cerr << error << std::endl;
-  negativeReply(interest, 401);
-}
 
 void
 WatchHandle::onData(const Interest& interest, const ndn::Data& data, const Name& name)
 {
-  m_validator.validate(data,
-                       bind(&WatchHandle::onDataValidated, this, interest, _1, name),
-                       bind(&WatchHandle::onDataValidationFailed, this, interest, _1, _2, name));
+ m_validator.validate(data,
+                      bind(&WatchHandle::onDataValidated, this, interest, _1, name),
+                      bind(&WatchHandle::onDataValidationFailed, this, interest, _1, _2, name));
 }
 
 void
@@ -99,7 +92,7 @@
   if (!m_processes[name].second) {
     return;
   }
-  if (getStorageHandle().insertData(data)) {
+  if (storageHandle.insertData(data)) {
     m_size++;
     if (!onRunning(name))
       return;
@@ -125,7 +118,7 @@
     }
 
     ++m_interestNum;
-    getFace().expressInterest(fetchInterest,
+    face.expressInterest(fetchInterest,
                               bind(&WatchHandle::onData, this, _1, _2, name),
                               bind(&WatchHandle::onTimeout, this, _1, name), // Nack
                               bind(&WatchHandle::onTimeout, this, _1, name));
@@ -168,7 +161,7 @@
   }
 
   ++m_interestNum;
-  getFace().expressInterest(fetchInterest,
+  face.expressInterest(fetchInterest,
                             bind(&WatchHandle::onData, this, _1, _2, name),
                             bind(&WatchHandle::onTimeout, this, _1, name), // Nack
                             bind(&WatchHandle::onTimeout, this, _1, name));
@@ -190,7 +183,7 @@
   fetchInterest.setChildSelector(1);
 
   ++m_interestNum;
-  getFace().expressInterest(fetchInterest,
+  face.expressInterest(fetchInterest,
                             bind(&WatchHandle::onData, this, _1, _2, name),
                             bind(&WatchHandle::onTimeout, this, _1, name), // Nack
                             bind(&WatchHandle::onTimeout, this, _1, name));
@@ -198,112 +191,60 @@
 }
 
 void
-WatchHandle::listen(const Name& prefix)
+WatchHandle::handleStopCommand(const Name& prefix, const Interest& interest,
+                               const ndn::mgmt::ControlParameters& parameter,
+                               const ndn::mgmt::CommandContinuation& done)
 {
-  getFace().setInterestFilter(Name(prefix).append("watch").append("start"),
-                              bind(&WatchHandle::onInterest, this, _1, _2));
-  getFace().setInterestFilter(Name(prefix).append("watch").append("check"),
-                              bind(&WatchHandle::onCheckInterest, this, _1, _2));
-  getFace().setInterestFilter(Name(prefix).append("watch").append("stop"),
-                              bind(&WatchHandle::onStopInterest, this, _1, _2));
+  const RepoCommandParameter& repoParameter = dynamic_cast<const RepoCommandParameter&>(parameter);
+
+  watchStop(repoParameter.getName());
+  std::string text = "Watched Prefix Insertion for prefix (" + prefix.toUri() + ") is stop.";
+  return done(RepoCommandResponse(101, text));
 }
 
 void
-WatchHandle::onStopInterest(const Name& prefix, const Interest& interest)
+WatchHandle::handleCheckCommand(const Name& prefix, const Interest& interest,
+                                const ndn::mgmt::ControlParameters& parameter,
+                                const ndn::mgmt::CommandContinuation& done)
 {
-  m_validator.validate(interest,
-                       bind(&WatchHandle::onStopValidated, this, _1, prefix),
-                       bind(&WatchHandle::onStopValidationFailed, this, _1, _2));
-}
+  const RepoCommandParameter& repoParameter = dynamic_cast<const RepoCommandParameter&>(parameter);
 
-void
-WatchHandle::onStopValidated(const Interest& interest, const Name& prefix)
-{
-  RepoCommandParameter parameter;
-  try {
-    extractParameter(interest, prefix, parameter);
-  }
-  catch (const RepoCommandParameter::Error&) {
-    negativeReply(interest, 403);
-    return;
-  }
-
-  watchStop(parameter.getName());
-  negativeReply(interest, 101);
-}
-
-void
-WatchHandle::onStopValidationFailed(const Interest& interest, const ValidationError& error)
-{
-  std::cerr << error << std::endl;
-  negativeReply(interest, 401);
-}
-
-void
-WatchHandle::onCheckInterest(const Name& prefix, const Interest& interest)
-{
-  m_validator.validate(interest,
-                       bind(&WatchHandle::onCheckValidated, this, _1, prefix),
-                       bind(&WatchHandle::onCheckValidationFailed, this, _1, _2));
-}
-
-void
-WatchHandle::onCheckValidated(const Interest& interest, const Name& prefix)
-{
-  RepoCommandParameter parameter;
-  try {
-    extractParameter(interest, prefix, parameter);
-  }
-  catch (const RepoCommandParameter::Error&) {
-    negativeReply(interest, 403);
-    return;
-  }
-
-  if (!parameter.hasName()) {
-    negativeReply(interest, 403);
-    return;
-  }
   //check whether this process exists
-  Name name = parameter.getName();
+  Name name = repoParameter.getName();
   if (m_processes.count(name) == 0) {
     std::cerr << "no such process name: " << name << std::endl;
-    negativeReply(interest, 404);
-    return;
+    RepoCommandResponse response(404, "No such process is in progress");
+    response.setBody(response.wireEncode());
+    return done(response);
   }
 
   RepoCommandResponse& response = m_processes[name].first;
-    if (!m_processes[name].second) {
-    response.setStatusCode(101);
+
+  if (!m_processes[name].second) {
+    response.setCode(101);
   }
 
-  reply(interest, response);
-
-}
-
-void
-WatchHandle::onCheckValidationFailed(const Interest& interest, const ValidationError& error)
-{
-  std::cerr << error << std::endl;
-  negativeReply(interest, 401);
+  return done(response);
 }
 
 void
 WatchHandle::deferredDeleteProcess(const Name& name)
 {
-  getScheduler().scheduleEvent(PROCESS_DELETE_TIME,
+  scheduler.scheduleEvent(PROCESS_DELETE_TIME,
                                bind(&WatchHandle::deleteProcess, this, name));
 }
 
 void
 WatchHandle::processWatchCommand(const Interest& interest,
-                                 RepoCommandParameter& parameter)
+                                 const RepoCommandParameter& parameter,
+                                 const ndn::mgmt::CommandContinuation& done)
 {
   // if there is no watchTimeout specified, m_watchTimeout will be set as 0 and this handle will run forever
   if (parameter.hasWatchTimeout()) {
     m_watchTimeout = parameter.getWatchTimeout();
   }
   else {
-    m_watchTimeout = milliseconds(0);
+    m_watchTimeout = 0_ms;
   }
 
   // if there is no maxInterestNum specified, m_maxInterestNum will be 0, which means infinity
@@ -318,10 +259,14 @@
     m_interestLifetime = parameter.getInterestLifetime();
   }
 
-  reply(interest, RepoCommandResponse().setStatusCode(100));
+  RepoCommandResponse response(100, "Watching the prefix started.");
+  response.setBody(response.wireEncode());
+  done(response);
 
   m_processes[parameter.getName()] =
-                std::make_pair(RepoCommandResponse().setStatusCode(300), true);
+                std::make_pair(RepoCommandResponse(300, "This watched prefix Insertion is in progress"),
+                               true);
+
   Interest fetchInterest(parameter.getName());
   if (parameter.hasSelectors()) {
     fetchInterest.setSelectors(parameter.getSelectors());
@@ -330,19 +275,10 @@
   fetchInterest.setInterestLifetime(m_interestLifetime);
   m_startTime = steady_clock::now();
   m_interestNum++;
-  getFace().expressInterest(fetchInterest,
-                            bind(&WatchHandle::onData, this, _1, _2, parameter.getName()),
-                            bind(&WatchHandle::onTimeout, this, _1, parameter.getName()), // Nack
-                            bind(&WatchHandle::onTimeout, this, _1, parameter.getName()));
-}
-
-
-void
-WatchHandle::negativeReply(const Interest& interest, int statusCode)
-{
-  RepoCommandResponse response;
-  response.setStatusCode(statusCode);
-  reply(interest, response);
+  face.expressInterest(fetchInterest,
+                       bind(&WatchHandle::onData, this, _1, _2, parameter.getName()),
+                       bind(&WatchHandle::onTimeout, this, _1, parameter.getName()), // Nack
+                       bind(&WatchHandle::onTimeout, this, _1, parameter.getName()));
 }
 
 bool
diff --git a/src/handles/watch-handle.hpp b/src/handles/watch-handle.hpp
index c7071df..221b67d 100644
--- a/src/handles/watch-handle.hpp
+++ b/src/handles/watch-handle.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017, Regents of the University of California.
+ * Copyright (c) 2014-2018, Regents of the University of California.
  *
  * This file is part of NDN repo-ng (Next generation of NDN repository).
  * See AUTHORS.md for complete list of repo-ng authors and contributors.
@@ -20,7 +20,9 @@
 #ifndef REPO_HANDLES_WATCH_HANDLE_HPP
 #define REPO_HANDLES_WATCH_HANDLE_HPP
 
-#include "base-handle.hpp"
+#include "command-base-handle.hpp"
+
+#include <ndn-cxx/mgmt/dispatcher.hpp>
 
 #include <queue>
 
@@ -38,40 +40,37 @@
  * watching the prefix until a command interest tell it to stop, the total
  * amount of sent interests reaches a specific number or time out.
  */
-class WatchHandle : public BaseHandle
+class WatchHandle : public CommandBaseHandle
 {
 
 public:
-  class Error : public BaseHandle::Error
+  class Error : public CommandBaseHandle::Error
   {
   public:
     explicit
     Error(const std::string& what)
-      : BaseHandle::Error(what)
+      : CommandBaseHandle::Error(what)
     {
     }
   };
 
 
 public:
-  WatchHandle(Face& face, RepoStorage& storageHandle, KeyChain& keyChain,
-              Scheduler& scheduler, Validator& validator);
-
-  virtual void
-  listen(const Name& prefix);
+  WatchHandle(Face& face, RepoStorage& storageHandle,
+              ndn::mgmt::Dispatcher& dispatcher, Scheduler& scheduler,
+              Validator& validator);
 
 private: // watch-insert command
   /**
    * @brief handle watch commands
    */
-  void
-  onInterest(const Name& prefix, const Interest& interest);
 
   void
-  onValidated(const Interest& interest, const Name& prefix);
-
+  handleStartCommand(const Name& prefix, const Interest& interest,
+                     const ndn::mgmt::ControlParameters& parameters,
+                     const ndn::mgmt::CommandContinuation& done);
   void
-  onValidationFailed(const Interest& interest, const ValidationError& error);
+  onValidationFailed(const std::shared_ptr<const Interest>& interest, const std::string& reason);
 
 private: // data fetching
   /**
@@ -98,7 +97,8 @@
 
 
   void
-  processWatchCommand(const Interest& interest, RepoCommandParameter& parameter);
+  processWatchCommand(const Interest& interest, const RepoCommandParameter& parameter,
+                      const ndn::mgmt::CommandContinuation& done);
 
   void
   watchStop(const Name& name);
@@ -107,11 +107,11 @@
   /**
    * @brief handle watch check command
    */
-  void
-  onCheckInterest(const Name& prefix, const Interest& interest);
 
   void
-  onCheckValidated(const Interest& interest, const Name& prefix);
+  handleCheckCommand(const Name& prefix, const Interest& interest,
+                     const ndn::mgmt::ControlParameters& parameters,
+                     const ndn::mgmt::CommandContinuation& done);
 
   void
   onCheckValidationFailed(const Interest& interest, const ValidationError& error);
@@ -120,20 +120,17 @@
   /**
    * @brief handle watch stop command
    */
-  void
-  onStopInterest(const Name& prefix, const Interest& interest);
 
   void
-  onStopValidated(const Interest& interest, const Name& prefix);
+  handleStopCommand(const Name& prefix, const Interest& interest,
+                    const ndn::mgmt::ControlParameters& parameters,
+                    const ndn::mgmt::CommandContinuation& done);
 
   void
   onStopValidationFailed(const Interest& interest, const ValidationError& error);
 
 private:
   void
-  negativeReply(const Interest& interest, int statusCode);
-
-  void
   deferredDeleteProcess(const Name& name);
 
   void
@@ -144,7 +141,6 @@
 
 private:
   Validator& m_validator;
-
   map<Name, std::pair<RepoCommandResponse, bool> > m_processes;
   int64_t m_interestNum;
   int64_t m_maxInterestNum;
diff --git a/src/handles/write-handle.cpp b/src/handles/write-handle.cpp
index 0283728..6cc9583 100644
--- a/src/handles/write-handle.cpp
+++ b/src/handles/write-handle.cpp
@@ -19,24 +19,34 @@
 
 #include "write-handle.hpp"
 
+#include <ndn-cxx/util/random.hpp>
+
 namespace repo {
 
 static const int RETRY_TIMEOUT = 3;
 static const int DEFAULT_CREDIT = 12;
-static const milliseconds NOEND_TIMEOUT(10000);
-static const milliseconds PROCESS_DELETE_TIME(10000);
-static const milliseconds DEFAULT_INTEREST_LIFETIME(4000);
+static const milliseconds NOEND_TIMEOUT(10000_ms);
+static const milliseconds PROCESS_DELETE_TIME(10000_ms);
+static const milliseconds DEFAULT_INTEREST_LIFETIME(4000_ms);
 
-WriteHandle::WriteHandle(Face& face, RepoStorage& storageHandle, KeyChain& keyChain,
-                         Scheduler& scheduler,
-                         Validator& validator)
-  : BaseHandle(face, storageHandle, keyChain, scheduler)
+WriteHandle::WriteHandle(Face& face, RepoStorage& storageHandle, ndn::mgmt::Dispatcher& dispatcher,
+                         Scheduler& scheduler, Validator& validator)
+  : CommandBaseHandle(face, storageHandle, scheduler, validator)
   , m_validator(validator)
   , m_retryTime(RETRY_TIMEOUT)
   , m_credit(DEFAULT_CREDIT)
   , m_noEndTimeout(NOEND_TIMEOUT)
   , m_interestLifetime(DEFAULT_INTEREST_LIFETIME)
 {
+  dispatcher.addControlCommand<RepoCommandParameter>(ndn::PartialName("insert"),
+    makeAuthorization(),
+    std::bind(&WriteHandle::validateParameters<InsertCommand>, this, _1),
+    std::bind(&WriteHandle::handleInsertCommand, this, _1, _2, _3, _4));
+
+  dispatcher.addControlCommand<RepoCommandParameter>(ndn::PartialName("insert check"),
+    makeAuthorization(),
+    std::bind(&WriteHandle::validateParameters<InsertCheckCommand>, this, _1),
+    std::bind(&WriteHandle::handleCheckCommand, this, _1, _2, _3, _4));
 }
 
 void
@@ -45,46 +55,26 @@
   m_processes.erase(processId);
 }
 
-// Interest.
 void
-WriteHandle::onInterest(const Name& prefix, const Interest& interest)
+WriteHandle::handleInsertCommand(const Name& prefix, const Interest& interest,
+                                 const ndn::mgmt::ControlParameters& parameter,
+                                 const ndn::mgmt::CommandContinuation& done)
 {
-  m_validator.validate(interest,
-                       bind(&WriteHandle::onValidated, this, _1, prefix),
-                       bind(&WriteHandle::onValidationFailed, this, _1, _2));
-}
+  RepoCommandParameter* repoParameter =
+    dynamic_cast<RepoCommandParameter*>(const_cast<ndn::mgmt::ControlParameters*>(&parameter));
 
-void
-WriteHandle::onValidated(const Interest& interest, const Name& prefix)
-{
-  RepoCommandParameter parameter;
-  try {
-    extractParameter(interest, prefix, parameter);
-  }
-  catch (const RepoCommandParameter::Error&) {
-    negativeReply(interest, 403);
-    return;
-  }
-
-  if (parameter.hasStartBlockId() || parameter.hasEndBlockId()) {
-    if (parameter.hasSelectors()) {
-      negativeReply(interest, 402);
+  if (repoParameter->hasStartBlockId() || repoParameter->hasEndBlockId()) {
+    if (repoParameter->hasSelectors()) {
+      done(negativeReply("BlockId present. BlockId is not supported in this protocol", 402));
       return;
     }
-    processSegmentedInsertCommand(interest, parameter);
+    processSegmentedInsertCommand(interest, *repoParameter, done);
   }
   else {
-    processSingleInsertCommand(interest, parameter);
+    processSingleInsertCommand(interest, *repoParameter, done);
   }
-  if (parameter.hasInterestLifetime())
-    m_interestLifetime = parameter.getInterestLifetime();
-}
-
-void
-WriteHandle::onValidationFailed(const Interest& interest, const ValidationError& error)
-{
-  std::cerr << error << std::endl;
-  negativeReply(interest, 401);
+  if (repoParameter->hasInterestLifetime())
+    m_interestLifetime = repoParameter->getInterestLifetime();
 }
 
 void
@@ -106,9 +96,7 @@
   RepoCommandResponse& response = process.response;
 
   if (response.getInsertNum() == 0) {
-    getStorageHandle().insertData(data);
-   // getStorageHandle().insertEntry(data);
-   // getStoreIndex().insert(data);
+    storageHandle.insertData(data);
     response.setInsertNum(1);
   }
 
@@ -153,7 +141,7 @@
   }
 
   //insert data
-  if (getStorageHandle().insertData(data)) {
+  if (storageHandle.insertData(data)) {
     response.setInsertNum(response.getInsertNum() + 1);
   }
 
@@ -176,15 +164,6 @@
 }
 
 void
-WriteHandle::listen(const Name& prefix)
-{
-  getFace().setInterestFilter(Name(prefix).append("insert"),
-                              bind(&WriteHandle::onInterest, this, _1, _2));
-  getFace().setInterestFilter(Name(prefix).append("insert check"),
-                              bind(&WriteHandle::onCheckInterest, this, _1, _2));
-}
-
-void
 WriteHandle::segInit(ProcessId processId, const RepoCommandParameter& parameter)
 {
   ProcessInfo& process = m_processes[processId];
@@ -214,7 +193,7 @@
     fetchName.appendSegment(segment);
     Interest interest(fetchName);
     interest.setInterestLifetime(m_interestLifetime);
-    getFace().expressInterest(interest,
+    face.expressInterest(interest,
                               bind(&WriteHandle::onSegmentData, this, _1, _2, processId),
                               bind(&WriteHandle::onSegmentTimeout, this, _1, processId), // Nack
                               bind(&WriteHandle::onSegmentTimeout, this, _1, processId));
@@ -254,7 +233,7 @@
       std::cerr << "noEndtimeout: " << processId << std::endl;
       //m_processes.erase(processId);
       //StatusCode should be refreshed as 405
-      response.setStatusCode(405);
+      response.setCode(405);
       //schedule a delete event
       deferredDeleteProcess(processId);
       return;
@@ -268,7 +247,7 @@
     if (response.getInsertNum() >= nSegments) {
       //m_processes.erase(processId);
       //All the data has been inserted, StatusCode is refreshed as 200
-      response.setStatusCode(200);
+      response.setCode(200);
       deferredDeleteProcess(processId);
       return;
     }
@@ -309,7 +288,7 @@
   fetchName.appendSegment(sendingSegment);
   Interest fetchInterest(fetchName);
   fetchInterest.setInterestLifetime(m_interestLifetime);
-  getFace().expressInterest(fetchInterest,
+  face.expressInterest(fetchInterest,
                             bind(&WriteHandle::onSegmentData, this, _1, _2, processId),
                             bind(&WriteHandle::onSegmentTimeout, this, _1, processId), // Nack
                             bind(&WriteHandle::onSegmentTimeout, this, _1, processId));
@@ -361,7 +340,7 @@
     retryTime++;
     Interest retryInterest(interest.getName());
     retryInterest.setInterestLifetime(m_interestLifetime);
-    getFace().expressInterest(retryInterest,
+    face.expressInterest(retryInterest,
                               bind(&WriteHandle::onSegmentData, this, _1, _2, processId),
                               bind(&WriteHandle::onSegmentTimeout, this, _1, processId), // Nack
                               bind(&WriteHandle::onSegmentTimeout, this, _1, processId));
@@ -370,35 +349,17 @@
 }
 
 void
-WriteHandle::onCheckInterest(const Name& prefix, const Interest& interest)
+WriteHandle::handleCheckCommand(const Name& prefix, const Interest& interest,
+                                const ndn::mgmt::ControlParameters& parameter,
+                                const ndn::mgmt::CommandContinuation& done)
 {
-  m_validator.validate(interest,
-                       bind(&WriteHandle::onCheckValidated, this, _1, prefix),
-                       bind(&WriteHandle::onCheckValidationFailed, this, _1, _2));
+  const RepoCommandParameter& repoParameter = dynamic_cast<const RepoCommandParameter&>(parameter);
 
-}
-
-void
-WriteHandle::onCheckValidated(const Interest& interest, const Name& prefix)
-{
-  RepoCommandParameter parameter;
-  try {
-    extractParameter(interest, prefix, parameter);
-  }
-  catch (const RepoCommandParameter::Error&) {
-    negativeReply(interest, 403);
-    return;
-  }
-
-  if (!parameter.hasProcessId()) {
-    negativeReply(interest, 403);
-    return;
-  }
   //check whether this process exists
-  ProcessId processId = parameter.getProcessId();
+  ProcessId processId = repoParameter.getProcessId();
   if (m_processes.count(processId) == 0) {
     std::cerr << "no such processId: " << processId << std::endl;
-    negativeReply(interest, 404);
+    done(negativeReply("No such this process is in progress", 404));
     return;
   }
 
@@ -409,109 +370,100 @@
   //Check whether it is single data fetching
   if (!response.hasStartBlockId() &&
       !response.hasEndBlockId()) {
-    reply(interest, response);
+    //reply(interest, response);
+    done(response);
     return;
   }
 
   //read if noEndtimeout
   if (!response.hasEndBlockId()) {
     extendNoEndTime(process);
-    reply(interest, response);
+    done(response);
     return;
   }
   else {
-    reply(interest, response);
+    done(response);
   }
 }
 
 void
-WriteHandle::onCheckValidationFailed(const Interest& interest, const ValidationError& error)
-{
-  std::cerr << error << std::endl;
-  negativeReply(interest, 401);
-}
-
-void
 WriteHandle::deferredDeleteProcess(ProcessId processId)
 {
-  getScheduler().scheduleEvent(PROCESS_DELETE_TIME,
+  scheduler.scheduleEvent(PROCESS_DELETE_TIME,
                                bind(&WriteHandle::deleteProcess, this, processId));
 }
 
 void
-WriteHandle::processSingleInsertCommand(const Interest& interest,
-                                        RepoCommandParameter& parameter)
+WriteHandle::processSingleInsertCommand(const Interest& interest, RepoCommandParameter& parameter,
+                                        const ndn::mgmt::CommandContinuation& done)
 {
-  ProcessId processId = generateProcessId();
+  ProcessId processId = ndn::random::generateWord64();
 
   ProcessInfo& process = m_processes[processId];
 
   RepoCommandResponse& response = process.response;
-  response.setStatusCode(100);
+  response.setCode(100);
   response.setProcessId(processId);
   response.setInsertNum(0);
+  response.setBody(response.wireEncode());
+  done(response);
 
-  reply(interest, response);
-
-  response.setStatusCode(300);
+  response.setCode(300);
 
   Interest fetchInterest(parameter.getName());
   fetchInterest.setInterestLifetime(m_interestLifetime);
   if (parameter.hasSelectors()) {
     fetchInterest.setSelectors(parameter.getSelectors());
   }
-  getFace().expressInterest(fetchInterest,
-                            bind(&WriteHandle::onData, this, _1, _2, processId),
-                            bind(&WriteHandle::onTimeout, this, _1, processId), // Nack
-                            bind(&WriteHandle::onTimeout, this, _1, processId));
+  face.expressInterest(fetchInterest,
+                       bind(&WriteHandle::onData, this, _1, _2, processId),
+                       bind(&WriteHandle::onTimeout, this, _1, processId), // Nack
+                       bind(&WriteHandle::onTimeout, this, _1, processId));
 }
 
 void
-WriteHandle::processSegmentedInsertCommand(const Interest& interest,
-                                           RepoCommandParameter& parameter)
+WriteHandle::processSegmentedInsertCommand(const Interest& interest, RepoCommandParameter& parameter,
+                                           const ndn::mgmt::CommandContinuation& done)
 {
   if (parameter.hasEndBlockId()) {
     //normal fetch segment
-    if (!parameter.hasStartBlockId()) {
-      parameter.setStartBlockId(0);
-    }
-
-    SegmentNo startBlockId = parameter.getStartBlockId();
+    SegmentNo startBlockId = parameter.hasStartBlockId() ? parameter.getStartBlockId() : 0;
     SegmentNo endBlockId = parameter.getEndBlockId();
     if (startBlockId > endBlockId) {
-      negativeReply(interest, 403);
+      done(negativeReply("Malformed Command", 403));
       return;
     }
 
-    ProcessId processId = generateProcessId();
+    ProcessId processId = ndn::random::generateWord64();
     ProcessInfo& process = m_processes[processId];
     RepoCommandResponse& response = process.response;
-    response.setStatusCode(100);
+    response.setCode(100);
     response.setProcessId(processId);
     response.setInsertNum(0);
     response.setStartBlockId(startBlockId);
     response.setEndBlockId(endBlockId);
-
-    reply(interest, response);
+    response.setBody(response.wireEncode());
+    done(response);
 
     //300 means data fetching is in progress
-    response.setStatusCode(300);
+    response.setCode(300);
 
     segInit(processId, parameter);
   }
   else {
     //no EndBlockId, so fetch FinalBlockId in data, if timeout, stop
-    ProcessId processId = generateProcessId();
+    ProcessId processId = ndn::random::generateWord64();
     ProcessInfo& process = m_processes[processId];
     RepoCommandResponse& response = process.response;
-    response.setStatusCode(100);
+    response.setCode(100);
     response.setProcessId(processId);
     response.setInsertNum(0);
     response.setStartBlockId(parameter.getStartBlockId());
-    reply(interest, response);
+    response.setBody(response.wireEncode());
+    done(response);
 
     //300 means data fetching is in progress
-    response.setStatusCode(300);
+    response.setCode(300);
 
     segInit(processId, parameter);
   }
@@ -524,21 +476,21 @@
   ndn::time::steady_clock::TimePoint now = ndn::time::steady_clock::now();
   RepoCommandResponse& response = process.response;
   if (now > noEndTime) {
-    response.setStatusCode(405);
+    response.setCode(405);
     return;
   }
   //extends noEndTime
-  process.noEndTime =
-    ndn::time::steady_clock::now() + m_noEndTimeout;
+  process.noEndTime = ndn::time::steady_clock::now() + m_noEndTimeout;
 
 }
 
-void
-WriteHandle::negativeReply(const Interest& interest, int statusCode)
+RepoCommandResponse
+WriteHandle::negativeReply(std::string text, int statusCode)
 {
-  RepoCommandResponse response;
-  response.setStatusCode(statusCode);
-  reply(interest, response);
+  RepoCommandResponse response(statusCode, text);
+  response.setBody(response.wireEncode());
+
+  return response;
 }
 
 } // namespace repo
diff --git a/src/handles/write-handle.hpp b/src/handles/write-handle.hpp
index c6622d9..686d68c 100644
--- a/src/handles/write-handle.hpp
+++ b/src/handles/write-handle.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017, Regents of the University of California.
+ * Copyright (c) 2014-2018, Regents of the University of California.
  *
  * This file is part of NDN repo-ng (Next generation of NDN repository).
  * See AUTHORS.md for complete list of repo-ng authors and contributors.
@@ -20,7 +20,9 @@
 #ifndef REPO_HANDLES_WRITE_HANDLE_HPP
 #define REPO_HANDLES_WRITE_HANDLE_HPP
 
-#include "base-handle.hpp"
+#include "command-base-handle.hpp"
+
+#include <ndn-cxx/mgmt/dispatcher.hpp>
 
 #include <queue>
 
@@ -51,27 +53,25 @@
  *
  * If repo cannot get FinalBlockId in noendTimeout time, the fetching process will terminate.
  */
-class WriteHandle : public BaseHandle
+class WriteHandle : public CommandBaseHandle
 {
 
 public:
-  class Error : public BaseHandle::Error
+  class Error : public CommandBaseHandle::Error
   {
   public:
     explicit
     Error(const std::string& what)
-      : BaseHandle::Error(what)
+      : CommandBaseHandle::Error(what)
     {
     }
   };
 
 
 public:
-  WriteHandle(Face& face, RepoStorage& storageHandle, KeyChain& keyChain,
-              Scheduler& scheduler, Validator& validator);
-
-  virtual void
-  listen(const Name& prefix);
+  WriteHandle(Face& face, RepoStorage& storageHandle,
+              ndn::mgmt::Dispatcher& dispatcher, Scheduler& scheduler,
+              Validator& validator);
 
 private:
   /**
@@ -104,10 +104,9 @@
    * @brief handle insert commands
    */
   void
-  onInterest(const Name& prefix, const Interest& interest);
-
-  void
-  onValidated(const Interest& interest, const Name& prefix);
+  handleInsertCommand(const Name& prefix, const Interest& interest,
+                      const ndn::mgmt::ControlParameters& parameters,
+                      const ndn::mgmt::CommandContinuation& done);
 
   void
   onValidationFailed(const Interest& interest, const ValidationError& error);
@@ -129,7 +128,8 @@
   onTimeout(const Interest& interest, ProcessId processId);
 
   void
-  processSingleInsertCommand(const Interest& interest, RepoCommandParameter& parameter);
+  processSingleInsertCommand(const Interest& interest, RepoCommandParameter& parameter,
+                             const ndn::mgmt::CommandContinuation& done);
 
 private:  // segmented data fetching
   /**
@@ -166,7 +166,8 @@
   onSegmentTimeoutControl(ProcessId processId, const Interest& interest);
 
   void
-  processSegmentedInsertCommand(const Interest& interest, RepoCommandParameter& parameter);
+  processSegmentedInsertCommand(const Interest& interest, RepoCommandParameter& parameter,
+                                const ndn::mgmt::CommandContinuation& done);
 
 private:
   /**
@@ -188,11 +189,11 @@
   /**
    * @brief handle insert check command
    */
-  void
-  onCheckInterest(const Name& prefix, const Interest& interest);
 
   void
-  onCheckValidated(const Interest& interest, const Name& prefix);
+  handleCheckCommand(const Name& prefix, const Interest& interest,
+                     const ndn::mgmt::ControlParameters& parameters,
+                     const ndn::mgmt::CommandContinuation& done);
 
   void
   onCheckValidationFailed(const Interest& interest, const ValidationError& error);
@@ -207,14 +208,12 @@
   void
   deferredDeleteProcess(ProcessId processId);
 
-  void
-  negativeReply(const Interest& interest, int statusCode);
+  RepoCommandResponse
+  negativeReply(std::string text, int statusCode);
 
 private:
   Validator& m_validator;
-
   map<ProcessId, ProcessInfo> m_processes;
-
   int m_retryTime;
   int m_credit;
   ndn::time::milliseconds m_noEndTimeout;
diff --git a/src/repo-command-parameter.cpp b/src/repo-command-parameter.cpp
new file mode 100644
index 0000000..e7f7e15
--- /dev/null
+++ b/src/repo-command-parameter.cpp
@@ -0,0 +1,294 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2018, Regents of the University of California.
+ *
+ * This file is part of NDN repo-ng (Next generation of NDN repository).
+ * See AUTHORS.md for complete list of repo-ng authors and contributors.
+ *
+ * repo-ng 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.
+ *
+ * repo-ng 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
+ * repo-ng, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "repo-command-parameter.hpp"
+
+#include <ndn-cxx/encoding/encoding-buffer.hpp>
+#include <ndn-cxx/encoding/block-helpers.hpp>
+#include <ndn-cxx/name.hpp>
+#include <ndn-cxx/selectors.hpp>
+#include <ndn-cxx/mgmt/control-parameters.hpp>
+
+namespace repo {
+
+RepoCommandParameter&
+RepoCommandParameter::setName(const Name& name)
+{
+  m_name = name;
+  m_hasFields[REPO_PARAMETER_NAME] = true;
+  m_wire.reset();
+  return *this;
+}
+
+RepoCommandParameter&
+RepoCommandParameter::setSelectors(const Selectors& selectors)
+{
+  m_selectors = selectors;
+  m_wire.reset();
+  return *this;
+}
+
+RepoCommandParameter&
+RepoCommandParameter::setStartBlockId(uint64_t startBlockId)
+{
+  m_startBlockId  = startBlockId;
+  m_hasFields[REPO_PARAMETER_START_BLOCK_ID] = true;
+  m_wire.reset();
+  return *this;
+}
+
+RepoCommandParameter&
+RepoCommandParameter::setEndBlockId(uint64_t endBlockId)
+{
+  m_endBlockId  = endBlockId;
+  m_hasFields[REPO_PARAMETER_END_BLOCK_ID] = true;
+  m_wire.reset();
+  return *this;
+}
+
+RepoCommandParameter&
+RepoCommandParameter::setProcessId(uint64_t processId)
+{
+  m_processId = processId;
+  m_hasFields[REPO_PARAMETER_PROCESS_ID] = true;
+  m_wire.reset();
+  return *this;
+}
+
+RepoCommandParameter&
+RepoCommandParameter::setMaxInterestNum(uint64_t maxInterestNum)
+{
+  m_maxInterestNum = maxInterestNum;
+  m_hasFields[REPO_PARAMETER_MAX_INTEREST_NUM] = true;
+  m_wire.reset();
+  return *this;
+}
+
+RepoCommandParameter&
+RepoCommandParameter::setWatchTimeout(milliseconds watchTimeout)
+{
+  m_watchTimeout = watchTimeout;
+  m_hasFields[REPO_PARAMETER_WATCH_TIME_OUT] = true;
+  m_wire.reset();
+  return *this;
+}
+
+RepoCommandParameter&
+RepoCommandParameter::setInterestLifetime(milliseconds interestLifetime)
+{
+  m_interestLifetime = interestLifetime;
+  m_hasFields[REPO_PARAMETER_INTEREST_LIFETIME] = true;
+  m_wire.reset();
+  return *this;
+}
+
+template<ndn::encoding::Tag T>
+size_t
+RepoCommandParameter::wireEncode(EncodingImpl<T>& encoder) const
+{
+  size_t totalLength = 0;
+  size_t variableLength = 0;
+
+  if (m_hasFields[REPO_PARAMETER_PROCESS_ID]) {
+    variableLength = encoder.prependNonNegativeInteger(m_processId);
+    totalLength += variableLength;
+    totalLength += encoder.prependVarNumber(variableLength);
+    totalLength += encoder.prependVarNumber(tlv::ProcessId);
+  }
+
+  if (m_hasFields[REPO_PARAMETER_END_BLOCK_ID]) {
+    variableLength = encoder.prependNonNegativeInteger(m_endBlockId);
+    totalLength += variableLength;
+    totalLength += encoder.prependVarNumber(variableLength);
+    totalLength += encoder.prependVarNumber(tlv::EndBlockId);
+  }
+
+  if (m_hasFields[REPO_PARAMETER_START_BLOCK_ID]) {
+    variableLength = encoder.prependNonNegativeInteger(m_startBlockId);
+    totalLength += variableLength;
+    totalLength += encoder.prependVarNumber(variableLength);
+    totalLength += encoder.prependVarNumber(tlv::StartBlockId);
+  }
+
+  if (m_hasFields[REPO_PARAMETER_MAX_INTEREST_NUM]) {
+    variableLength = encoder.prependNonNegativeInteger(m_maxInterestNum);
+    totalLength += variableLength;
+    totalLength += encoder.prependVarNumber(variableLength);
+    totalLength += encoder.prependVarNumber(tlv::MaxInterestNum);
+  }
+
+  if (m_hasFields[REPO_PARAMETER_WATCH_TIME_OUT]) {
+    variableLength = encoder.prependNonNegativeInteger(m_watchTimeout.count());
+    totalLength += variableLength;
+    totalLength += encoder.prependVarNumber(variableLength);
+    totalLength += encoder.prependVarNumber(tlv::WatchTimeout);
+  }
+
+  if (m_hasFields[REPO_PARAMETER_INTEREST_LIFETIME]) {
+    variableLength = encoder.prependNonNegativeInteger(m_interestLifetime.count());
+    totalLength += variableLength;
+    totalLength += encoder.prependVarNumber(variableLength);
+    totalLength += encoder.prependVarNumber(tlv::InterestLifetime);
+  }
+
+  if (!getSelectors().empty()) {
+    totalLength += getSelectors().wireEncode(encoder);
+  }
+
+  if (m_hasFields[REPO_PARAMETER_NAME]) {
+    totalLength += getName().wireEncode(encoder);
+  }
+
+  totalLength += encoder.prependVarNumber(totalLength);
+  totalLength += encoder.prependVarNumber(tlv::RepoCommandParameter);
+  return totalLength;
+}
+
+NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(RepoCommandParameter);
+
+Block
+RepoCommandParameter::wireEncode() const
+{
+  if (m_wire.hasWire())
+    return m_wire;
+
+  EncodingEstimator estimator;
+  size_t estimatedSize = wireEncode(estimator);
+
+  EncodingBuffer buffer(estimatedSize, 0);
+  wireEncode(buffer);
+
+  m_wire = buffer.block();
+  return m_wire;
+}
+
+void
+RepoCommandParameter::wireDecode(const Block& wire)
+{
+  m_wire = wire;
+
+  m_wire.parse();
+
+  if (m_wire.type() != tlv::RepoCommandParameter)
+    BOOST_THROW_EXCEPTION(Error("Requested decoding of RepoCommandParameter, but Block is of different type"));
+
+  // Name
+  Block::element_const_iterator val = m_wire.find(tlv::Name);
+  if (val != m_wire.elements_end())
+  {
+    m_hasFields[REPO_PARAMETER_NAME] = true;
+    m_name.wireDecode(m_wire.get(tlv::Name));
+  }
+
+  // Selectors
+  val = m_wire.find(tlv::Selectors);
+  if (val != m_wire.elements_end())
+  {
+    m_selectors.wireDecode(*val);
+  }
+  else
+    m_selectors = Selectors();
+
+  // StartBlockId
+  val = m_wire.find(tlv::StartBlockId);
+  if (val != m_wire.elements_end())
+  {
+    m_hasFields[REPO_PARAMETER_START_BLOCK_ID] = true;
+    m_startBlockId = readNonNegativeInteger(*val);
+  }
+
+  // EndBlockId
+  val = m_wire.find(tlv::EndBlockId);
+  if (val != m_wire.elements_end())
+  {
+    m_hasFields[REPO_PARAMETER_END_BLOCK_ID] = true;
+    m_endBlockId = readNonNegativeInteger(*val);
+  }
+
+  // ProcessId
+  val = m_wire.find(tlv::ProcessId);
+  if (val != m_wire.elements_end())
+  {
+    m_hasFields[REPO_PARAMETER_PROCESS_ID] = true;
+    m_processId = readNonNegativeInteger(*val);
+  }
+
+  // MaxInterestNum
+  val = m_wire.find(tlv::MaxInterestNum);
+  if (val != m_wire.elements_end())
+  {
+    m_hasFields[REPO_PARAMETER_MAX_INTEREST_NUM] = true;
+    m_maxInterestNum = readNonNegativeInteger(*val);
+  }
+
+  // WatchTimeout
+  val = m_wire.find(tlv::WatchTimeout);
+  if (val != m_wire.elements_end())
+  {
+    m_hasFields[REPO_PARAMETER_WATCH_TIME_OUT] = true;
+    m_watchTimeout = milliseconds(readNonNegativeInteger(*val));
+  }
+
+  // InterestLifeTime
+  val = m_wire.find(tlv::InterestLifetime);
+  if (val != m_wire.elements_end())
+  {
+    m_hasFields[REPO_PARAMETER_INTEREST_LIFETIME] = true;
+    m_interestLifetime = milliseconds(readNonNegativeInteger(*val));
+  }
+}
+
+std::ostream&
+operator<<(std::ostream& os, const RepoCommandParameter& repoCommandParameter)
+{
+  os << "RepoCommandParameter(";
+
+  // Name
+  if (repoCommandParameter.hasName()) {
+    os << " Name: " << repoCommandParameter.getName();
+  }
+  if (repoCommandParameter.hasStartBlockId()) {
+  // StartBlockId
+    os << " StartBlockId: " << repoCommandParameter.getStartBlockId();
+  }
+  // EndBlockId
+  if (repoCommandParameter.hasEndBlockId()) {
+    os << " EndBlockId: " << repoCommandParameter.getEndBlockId();
+  }
+  // ProcessId
+  if (repoCommandParameter.hasProcessId()) {
+    os << " ProcessId: " << repoCommandParameter.getProcessId();
+  }
+  // MaxInterestNum
+  if (repoCommandParameter.hasMaxInterestNum()) {
+    os << " MaxInterestNum: " << repoCommandParameter.getMaxInterestNum();
+  }
+  // WatchTimeout
+  if (repoCommandParameter.hasProcessId()) {
+    os << " WatchTimeout: " << repoCommandParameter.getWatchTimeout();
+  }
+  // InterestLifetime
+  if (repoCommandParameter.hasProcessId()) {
+    os << " InterestLifetime: " << repoCommandParameter.getInterestLifetime();
+  }
+  os << " )";
+  return os;
+}
+
+} // namespace repo
\ No newline at end of file
diff --git a/src/repo-command-parameter.hpp b/src/repo-command-parameter.hpp
index 97208b6..1ad212f 100644
--- a/src/repo-command-parameter.hpp
+++ b/src/repo-command-parameter.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017, Regents of the University of California.
+ * Copyright (c) 2014-2018, Regents of the University of California.
  *
  * This file is part of NDN repo-ng (Next generation of NDN repository).
  * See AUTHORS.md for complete list of repo-ng authors and contributors.
@@ -26,6 +26,7 @@
 #include <ndn-cxx/encoding/block-helpers.hpp>
 #include <ndn-cxx/name.hpp>
 #include <ndn-cxx/selectors.hpp>
+#include <ndn-cxx/mgmt/control-parameters.hpp>
 
 namespace repo {
 
@@ -37,12 +38,33 @@
 using ndn::EncodingBuffer;
 using namespace ndn::time;
 
+enum RepoParameterField {
+  REPO_PARAMETER_NAME,
+  REPO_PARAMETER_START_BLOCK_ID,
+  REPO_PARAMETER_END_BLOCK_ID,
+  REPO_PARAMETER_PROCESS_ID,
+  REPO_PARAMETER_MAX_INTEREST_NUM,
+  REPO_PARAMETER_WATCH_TIME_OUT,
+  REPO_PARAMETER_INTEREST_LIFETIME,
+  REPO_PARAMETER_UBOUND
+};
+
+const std::string REPO_PARAMETER_FIELD[REPO_PARAMETER_UBOUND] = {
+  "Name",
+  "StartBlockId",
+  "EndBlockId",
+  "ProcessId",
+  "MaxInterestNum",
+  "WatchTimeout",
+  "InterestLifetime"
+};
+
 /**
 * @brief Class defining abstraction of parameter of command for NDN Repo Protocol
 * @sa link https://redmine.named-data.net/projects/repo-ng/wiki/Repo_Protocol_Specification#RepoCommandParameter
 **/
 
-class RepoCommandParameter
+class RepoCommandParameter : public ndn::mgmt::ControlParameters
 {
 public:
   class Error : public ndn::tlv::Error
@@ -56,18 +78,13 @@
   };
 
   RepoCommandParameter()
-    : m_hasName(false)
-    , m_hasStartBlockId(false)
-    , m_hasEndBlockId(false)
-    , m_hasProcessId(false)
-    , m_hasMaxInterestNum(false)
-    , m_hasWatchTimeout(false)
-    , m_hasInterestLifetime(false)
+    : m_hasFields(REPO_PARAMETER_UBOUND)
   {
   }
 
   explicit
   RepoCommandParameter(const Block& block)
+    : m_hasFields(REPO_PARAMETER_UBOUND)
   {
     wireDecode(block);
   }
@@ -79,18 +96,12 @@
   }
 
   RepoCommandParameter&
-  setName(const Name& name)
-  {
-    m_name = name;
-    m_hasName = true;
-    m_wire.reset();
-    return *this;
-  }
+  setName(const Name& name);
 
   bool
   hasName() const
   {
-    return m_hasName;
+    return m_hasFields[REPO_PARAMETER_NAME];
   }
 
   const Selectors&
@@ -100,12 +111,7 @@
   }
 
   RepoCommandParameter&
-  setSelectors(const Selectors& selectors)
-  {
-    m_selectors = selectors;
-    m_wire.reset();
-    return *this;
-  }
+  setSelectors(const Selectors& selectors);
 
   bool
   hasSelectors() const
@@ -121,18 +127,12 @@
   }
 
   RepoCommandParameter&
-  setStartBlockId(uint64_t startBlockId)
-  {
-    m_startBlockId  = startBlockId;
-    m_hasStartBlockId = true;
-    m_wire.reset();
-    return *this;
-  }
+  setStartBlockId(uint64_t startBlockId);
 
   bool
   hasStartBlockId() const
   {
-    return m_hasStartBlockId;
+    return m_hasFields[REPO_PARAMETER_START_BLOCK_ID];
   }
 
   uint64_t
@@ -143,18 +143,12 @@
   }
 
   RepoCommandParameter&
-  setEndBlockId(uint64_t endBlockId)
-  {
-    m_endBlockId  = endBlockId;
-    m_hasEndBlockId = true;
-    m_wire.reset();
-    return *this;
-  }
+  setEndBlockId(uint64_t endBlockId);
 
   bool
   hasEndBlockId() const
   {
-    return m_hasEndBlockId;
+    return m_hasFields[REPO_PARAMETER_END_BLOCK_ID];
   }
 
   uint64_t
@@ -165,18 +159,12 @@
   }
 
   RepoCommandParameter&
-  setProcessId(uint64_t processId)
-  {
-    m_processId = processId;
-    m_hasProcessId = true;
-    m_wire.reset();
-    return *this;
-  }
+  setProcessId(uint64_t processId);
 
   bool
   hasProcessId() const
   {
-    return m_hasProcessId;
+    return m_hasFields[REPO_PARAMETER_PROCESS_ID];
   }
 
   uint64_t
@@ -187,18 +175,12 @@
   }
 
   RepoCommandParameter&
-  setMaxInterestNum(uint64_t maxInterestNum)
-  {
-    m_maxInterestNum = maxInterestNum;
-    m_hasMaxInterestNum = true;
-    m_wire.reset();
-    return *this;
-  }
+  setMaxInterestNum(uint64_t maxInterestNum);
 
   bool
   hasMaxInterestNum() const
   {
-    return m_hasMaxInterestNum;
+    return m_hasFields[REPO_PARAMETER_MAX_INTEREST_NUM];
   }
 
   milliseconds
@@ -209,18 +191,12 @@
   }
 
   RepoCommandParameter&
-  setWatchTimeout(milliseconds watchTimeout)
-  {
-    m_watchTimeout = watchTimeout;
-    m_hasWatchTimeout = true;
-    m_wire.reset();
-    return *this;
-  }
+  setWatchTimeout(milliseconds watchTimeout);
 
   bool
   hasWatchTimeout() const
   {
-    return m_hasWatchTimeout;
+    return m_hasFields[REPO_PARAMETER_WATCH_TIME_OUT];
   }
 
   milliseconds
@@ -231,32 +207,31 @@
   }
 
   RepoCommandParameter&
-  setInterestLifetime(milliseconds interestLifetime)
-  {
-    m_interestLifetime = interestLifetime;
-    m_hasInterestLifetime = true;
-    m_wire.reset();
-    return *this;
-  }
+  setInterestLifetime(milliseconds interestLifetime);
 
   bool
   hasInterestLifetime() const
   {
-    return m_hasInterestLifetime;
+    return m_hasFields[REPO_PARAMETER_INTEREST_LIFETIME];
+  }
+
+  const std::vector<bool>&
+  getPresentFields() const {
+    return m_hasFields;
   }
 
   template<ndn::encoding::Tag T>
   size_t
   wireEncode(EncodingImpl<T>& block) const;
 
-  const Block&
+  Block
   wireEncode() const;
 
   void
   wireDecode(const Block& wire);
 
 private:
-
+  std::vector<bool> m_hasFields;
   Name m_name;
   Selectors m_selectors;
   uint64_t m_startBlockId;
@@ -266,217 +241,10 @@
   milliseconds m_watchTimeout;
   milliseconds m_interestLifetime;
 
-  bool m_hasName;
-  bool m_hasStartBlockId;
-  bool m_hasEndBlockId;
-  bool m_hasProcessId;
-  bool m_hasMaxInterestNum;
-  bool m_hasWatchTimeout;
-  bool m_hasInterestLifetime;
-
   mutable Block m_wire;
 };
 
-template<ndn::encoding::Tag T>
-inline size_t
-RepoCommandParameter::wireEncode(EncodingImpl<T>& encoder) const
-{
-  size_t totalLength = 0;
-  size_t variableLength = 0;
-
-  if (m_hasProcessId) {
-    variableLength = encoder.prependNonNegativeInteger(m_processId);
-    totalLength += variableLength;
-    totalLength += encoder.prependVarNumber(variableLength);
-    totalLength += encoder.prependVarNumber(tlv::ProcessId);
-  }
-
-  if (m_hasEndBlockId) {
-    variableLength = encoder.prependNonNegativeInteger(m_endBlockId);
-    totalLength += variableLength;
-    totalLength += encoder.prependVarNumber(variableLength);
-    totalLength += encoder.prependVarNumber(tlv::EndBlockId);
-  }
-
-  if (m_hasStartBlockId) {
-    variableLength = encoder.prependNonNegativeInteger(m_startBlockId);
-    totalLength += variableLength;
-    totalLength += encoder.prependVarNumber(variableLength);
-    totalLength += encoder.prependVarNumber(tlv::StartBlockId);
-  }
-
-  if (m_hasMaxInterestNum) {
-    variableLength = encoder.prependNonNegativeInteger(m_maxInterestNum);
-    totalLength += variableLength;
-    totalLength += encoder.prependVarNumber(variableLength);
-    totalLength += encoder.prependVarNumber(tlv::MaxInterestNum);
-  }
-
-  if (m_hasWatchTimeout) {
-    variableLength = encoder.prependNonNegativeInteger(m_watchTimeout.count());
-    totalLength += variableLength;
-    totalLength += encoder.prependVarNumber(variableLength);
-    totalLength += encoder.prependVarNumber(tlv::WatchTimeout);
-  }
-
-  if (m_hasInterestLifetime) {
-    variableLength = encoder.prependNonNegativeInteger(m_interestLifetime.count());
-    totalLength += variableLength;
-    totalLength += encoder.prependVarNumber(variableLength);
-    totalLength += encoder.prependVarNumber(tlv::InterestLifetime);
-  }
-
-  if (!getSelectors().empty()) {
-    totalLength += getSelectors().wireEncode(encoder);
-  }
-
-  if (m_hasName) {
-    totalLength += getName().wireEncode(encoder);
-  }
-
-  totalLength += encoder.prependVarNumber(totalLength);
-  totalLength += encoder.prependVarNumber(tlv::RepoCommandParameter);
-  return totalLength;
-}
-
-inline const Block&
-RepoCommandParameter::wireEncode() const
-{
-  if (m_wire.hasWire())
-    return m_wire;
-
-  EncodingEstimator estimator;
-  size_t estimatedSize = wireEncode(estimator);
-
-  EncodingBuffer buffer(estimatedSize, 0);
-  wireEncode(buffer);
-
-  m_wire = buffer.block();
-  return m_wire;
-}
-
-inline void
-RepoCommandParameter::wireDecode(const Block& wire)
-{
-  m_hasName = false;
-  m_hasStartBlockId = false;
-  m_hasEndBlockId = false;
-  m_hasProcessId = false;
-  m_hasMaxInterestNum = false;
-  m_hasWatchTimeout = false;
-  m_hasInterestLifetime = false;
-
-  m_wire = wire;
-
-  m_wire.parse();
-
-  if (m_wire.type() != tlv::RepoCommandParameter)
-    BOOST_THROW_EXCEPTION(Error("Requested decoding of RepoCommandParameter, but Block is of different type"));
-
-  // Name
-  Block::element_const_iterator val = m_wire.find(tlv::Name);
-  if (val != m_wire.elements_end())
-  {
-    m_hasName = true;
-    m_name.wireDecode(m_wire.get(tlv::Name));
-  }
-
-  // Selectors
-  val = m_wire.find(tlv::Selectors);
-  if (val != m_wire.elements_end())
-  {
-    m_selectors.wireDecode(*val);
-  }
-  else
-    m_selectors = Selectors();
-
-  // StartBlockId
-  val = m_wire.find(tlv::StartBlockId);
-  if (val != m_wire.elements_end())
-  {
-    m_hasStartBlockId = true;
-    m_startBlockId = readNonNegativeInteger(*val);
-  }
-
-  // EndBlockId
-  val = m_wire.find(tlv::EndBlockId);
-  if (val != m_wire.elements_end())
-  {
-    m_hasEndBlockId = true;
-    m_endBlockId = readNonNegativeInteger(*val);
-  }
-
-  // ProcessId
-  val = m_wire.find(tlv::ProcessId);
-  if (val != m_wire.elements_end())
-  {
-    m_hasProcessId = true;
-    m_processId = readNonNegativeInteger(*val);
-  }
-
-  // MaxInterestNum
-  val = m_wire.find(tlv::MaxInterestNum);
-  if (val != m_wire.elements_end())
-  {
-    m_hasMaxInterestNum = true;
-    m_maxInterestNum = readNonNegativeInteger(*val);
-  }
-
-  // WatchTimeout
-  val = m_wire.find(tlv::WatchTimeout);
-  if (val != m_wire.elements_end())
-  {
-    m_hasWatchTimeout = true;
-    m_watchTimeout = milliseconds(readNonNegativeInteger(*val));
-  }
-
-  // InterestLiftTime
-  val = m_wire.find(tlv::InterestLifetime);
-  if (val != m_wire.elements_end())
-  {
-    m_hasInterestLifetime = true;
-    m_interestLifetime = milliseconds(readNonNegativeInteger(*val));
-  }
-
-
-}
-
-inline std::ostream&
-operator<<(std::ostream& os, const RepoCommandParameter& repoCommandParameter)
-{
-  os << "RepoCommandParameter(";
-
-  // Name
-  if (repoCommandParameter.hasName()) {
-    os << " Name: " << repoCommandParameter.getName();
-  }
-  if (repoCommandParameter.hasStartBlockId()) {
-  // StartBlockId
-    os << " StartBlockId: " << repoCommandParameter.getStartBlockId();
-  }
-  // EndBlockId
-  if (repoCommandParameter.hasEndBlockId()) {
-    os << " EndBlockId: " << repoCommandParameter.getEndBlockId();
-  }
-  // ProcessId
-  if (repoCommandParameter.hasProcessId()) {
-    os << " ProcessId: " << repoCommandParameter.getProcessId();
-  }
-  // MaxInterestNum
-  if (repoCommandParameter.hasMaxInterestNum()) {
-    os << " MaxInterestNum: " << repoCommandParameter.getMaxInterestNum();
-  }
-  // WatchTimeout
-  if (repoCommandParameter.hasProcessId()) {
-    os << " WatchTimeout: " << repoCommandParameter.getWatchTimeout();
-  }
-  // InterestLifetime
-  if (repoCommandParameter.hasProcessId()) {
-    os << " InterestLifetime: " << repoCommandParameter.getInterestLifetime();
-  }
-  os << " )";
-  return os;
-}
+NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(RepoCommandParameter);
 
 } // namespace repo
 
diff --git a/src/repo-command-response.cpp b/src/repo-command-response.cpp
new file mode 100644
index 0000000..d00a1d0
--- /dev/null
+++ b/src/repo-command-response.cpp
@@ -0,0 +1,283 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2018, Regents of the University of California.
+ *
+ * This file is part of NDN repo-ng (Next generation of NDN repository).
+ * See AUTHORS.md for complete list of repo-ng authors and contributors.
+ *
+ * repo-ng 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.
+ *
+ * repo-ng 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
+ * repo-ng, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "repo-command-response.hpp"
+
+namespace repo {
+
+RepoCommandResponse&
+RepoCommandResponse::setStartBlockId(uint64_t startBlockId)
+{
+  m_startBlockId  = startBlockId;
+  m_hasStartBlockId = true;
+  m_wire.reset();
+  return *this;
+}
+
+bool
+RepoCommandResponse::hasStartBlockId() const
+{
+  return m_hasStartBlockId;
+}
+
+RepoCommandResponse&
+RepoCommandResponse::setEndBlockId(uint64_t endBlockId)
+{
+  m_endBlockId  = endBlockId;
+  m_hasEndBlockId = true;
+  m_wire.reset();
+  return *this;
+}
+
+bool
+RepoCommandResponse::hasEndBlockId() const
+{
+  return m_hasEndBlockId;
+}
+
+RepoCommandResponse&
+RepoCommandResponse::setProcessId(uint64_t processId)
+{
+  m_processId  = processId;
+  m_hasProcessId = true;
+  m_wire.reset();
+  return *this;
+}
+
+bool
+RepoCommandResponse::hasProcessId() const
+{
+  return m_hasProcessId;
+}
+
+RepoCommandResponse&
+RepoCommandResponse::setCode(uint32_t statusCode)
+{
+  m_hasStatusCode = true;
+
+  RepoCommandResponse* response =
+    static_cast<RepoCommandResponse *> (&ndn::mgmt::ControlResponse::setCode(statusCode));
+  return *response;
+}
+
+bool
+RepoCommandResponse::hasStatusCode() const
+{
+  return m_hasStatusCode;
+}
+
+RepoCommandResponse&
+RepoCommandResponse::setInsertNum(uint64_t insertNum)
+{
+  m_insertNum = insertNum;
+  m_hasInsertNum = true;
+  m_wire.reset();
+  return *this;
+}
+
+bool
+RepoCommandResponse::hasInsertNum() const
+{
+  return m_hasInsertNum;
+}
+
+RepoCommandResponse&
+RepoCommandResponse::setDeleteNum(uint64_t deleteNum)
+{
+  m_deleteNum = deleteNum;
+  m_hasDeleteNum = true;
+  m_wire.reset();
+  return *this;
+}
+
+bool
+RepoCommandResponse::hasDeleteNum() const
+{
+  return m_hasDeleteNum;
+}
+
+const Block&
+RepoCommandResponse::wireEncode() const
+{
+  if (m_wire.hasWire())
+    return m_wire;
+
+  EncodingEstimator estimator;
+  size_t estimatedSize = wireEncode(estimator);
+
+  EncodingBuffer buffer(estimatedSize, 0);
+  wireEncode(buffer);
+
+  m_wire = buffer.block();
+  return m_wire;
+}
+
+
+template<ndn::encoding::Tag T>
+size_t
+RepoCommandResponse::wireEncode(EncodingImpl<T>& encoder) const
+{
+  size_t totalLength = 0;
+  size_t variableLength = 0;
+
+  if (m_hasDeleteNum) {
+    variableLength = encoder.prependNonNegativeInteger(m_deleteNum);
+    totalLength += variableLength;
+    totalLength += encoder.prependVarNumber(variableLength);
+    totalLength += encoder.prependVarNumber(tlv::DeleteNum);
+  }
+
+  if (m_hasInsertNum) {
+    variableLength = encoder.prependNonNegativeInteger(m_insertNum);
+    totalLength += variableLength;
+    totalLength += encoder.prependVarNumber(variableLength);
+    totalLength += encoder.prependVarNumber(tlv::InsertNum);
+  }
+
+  if (m_hasEndBlockId) {
+    variableLength = encoder.prependNonNegativeInteger(m_endBlockId);
+    totalLength += variableLength;
+    totalLength += encoder.prependVarNumber(variableLength);
+    totalLength += encoder.prependVarNumber(tlv::EndBlockId);
+  }
+
+  if (m_hasStartBlockId) {
+    variableLength = encoder.prependNonNegativeInteger(m_startBlockId);
+    totalLength += variableLength;
+    totalLength += encoder.prependVarNumber(variableLength);
+    totalLength += encoder.prependVarNumber(repo::tlv::StartBlockId);
+  }
+
+  if (m_hasStatusCode) {
+    variableLength = encoder.prependNonNegativeInteger(getCode());
+    totalLength += variableLength;
+    totalLength += encoder.prependVarNumber(variableLength);
+    totalLength += encoder.prependVarNumber(tlv::StatusCode);
+  }
+  else {
+    BOOST_THROW_EXCEPTION(Error("required field StatusCode is missing"));
+  }
+
+  if (m_hasProcessId) {
+    variableLength = encoder.prependNonNegativeInteger(m_processId);
+    totalLength += variableLength;
+    totalLength += encoder.prependVarNumber(variableLength);
+    totalLength += encoder.prependVarNumber(tlv::ProcessId);
+  }
+
+  totalLength += encoder.prependVarNumber(totalLength);
+  totalLength += encoder.prependVarNumber(tlv::RepoCommandResponse);
+  return totalLength;
+}
+
+void
+RepoCommandResponse::wireDecode(const Block& wire)
+{
+  m_hasStartBlockId = false;
+  m_hasEndBlockId = false;
+  m_hasProcessId = false;
+  m_hasStatusCode = false;
+  m_hasInsertNum = false;
+  m_hasDeleteNum = false;
+
+  m_wire = wire;
+
+  m_wire.parse();
+
+  Block::element_const_iterator val;
+
+  if (m_wire.type() != tlv::RepoCommandResponse)
+    BOOST_THROW_EXCEPTION(Error("RepoCommandResponse malformed"));
+
+  // StartBlockId
+  val = m_wire.find(tlv::StartBlockId);
+  if (val != m_wire.elements_end()) {
+    m_hasStartBlockId = true;
+    m_startBlockId = readNonNegativeInteger(*val);
+  }
+
+  // EndBlockId
+  val = m_wire.find(tlv::EndBlockId);
+  if (val != m_wire.elements_end()) {
+    m_hasEndBlockId = true;
+    m_endBlockId = readNonNegativeInteger(*val);
+  }
+
+  // ProcessId
+  val = m_wire.find(tlv::ProcessId);
+  if (val != m_wire.elements_end()) {
+    m_hasProcessId = true;
+    m_processId = readNonNegativeInteger(*val);
+  }
+
+  //StatusCode
+  val = m_wire.find(tlv::StatusCode);
+  if (val != m_wire.elements_end()) {
+    setCode(readNonNegativeInteger(*val));
+  }
+  else {
+    BOOST_THROW_EXCEPTION(Error("required field StatusCode is missing"));
+  }
+
+  // InsertNum
+  val = m_wire.find(tlv::InsertNum);
+  if (val != m_wire.elements_end()) {
+    m_hasInsertNum = true;
+    m_insertNum = readNonNegativeInteger(*val);
+  }
+
+  // DeleteNum
+  val = m_wire.find(tlv::DeleteNum);
+  if (val != m_wire.elements_end()) {
+    m_hasDeleteNum = true;
+    m_deleteNum = readNonNegativeInteger(*val);
+  }
+}
+
+NDN_CXX_DEFINE_WIRE_ENCODE_INSTANTIATIONS(RepoCommandResponse);
+
+std::ostream&
+operator<<(std::ostream& os, const RepoCommandResponse& repoCommandResponse)
+{
+  os << "RepoCommandResponse(";
+
+  if (repoCommandResponse.hasProcessId()) {
+    os << " ProcessId: " << repoCommandResponse.getProcessId();
+  }
+  // if (repoCommandResponse.hasStatusCode()) {
+  //   os << " StatusCode: " << repoCommandResponse.getStatusCode();
+  // }
+  if (repoCommandResponse.hasStartBlockId()) {
+    os << " StartBlockId: " << repoCommandResponse.getStartBlockId();
+  }
+  if (repoCommandResponse.hasEndBlockId()) {
+    os << " EndBlockId: " << repoCommandResponse.getEndBlockId();
+  }
+  if (repoCommandResponse.hasInsertNum()) {
+    os << " InsertNum: " << repoCommandResponse.getInsertNum();
+  }
+  if (repoCommandResponse.hasDeleteNum()) {
+    os << " DeleteNum: " << repoCommandResponse.getDeleteNum();
+
+  }
+  os << " )";
+  return os;
+}
+
+} // namespace repo
diff --git a/src/repo-command-response.hpp b/src/repo-command-response.hpp
index b07d894..a2432a7 100644
--- a/src/repo-command-response.hpp
+++ b/src/repo-command-response.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2014-2017, Regents of the University of California.
+/**
+ * Copyright (c) 2014-2018, Regents of the University of California.
  *
  * This file is part of NDN repo-ng (Next generation of NDN repository).
  * See AUTHORS.md for complete list of repo-ng authors and contributors.
@@ -22,6 +22,7 @@
 
 #include "repo-tlv.hpp"
 
+#include <ndn-cxx/mgmt/control-response.hpp>
 #include <ndn-cxx/encoding/block.hpp>
 #include <ndn-cxx/encoding/block-helpers.hpp>
 #include <ndn-cxx/encoding/encoding-buffer.hpp>
@@ -38,7 +39,7 @@
 * @brief Class defining abstraction of Response for NDN Repo Protocol
 * @sa link https://redmine.named-data.net/projects/repo-ng/wiki/Repo_Protocol_Specification#Repo-Command-Response
 */
-class RepoCommandResponse
+class RepoCommandResponse : public ndn::mgmt::ControlResponse
 {
 public:
   class Error : public ndn::tlv::Error
@@ -51,8 +52,9 @@
     }
   };
 
-  RepoCommandResponse()
-    : m_hasStartBlockId(false)
+  RepoCommandResponse(uint32_t code, const std::string& text)
+    : ndn::mgmt::ControlResponse(code, text)
+    , m_hasStartBlockId(false)
     , m_hasEndBlockId(false)
     , m_hasProcessId(false)
     , m_hasInsertNum(false)
@@ -61,6 +63,9 @@
   {
   }
 
+  RepoCommandResponse(){
+  }
+
   explicit
   RepoCommandResponse(const Block& block)
   {
@@ -74,19 +79,10 @@
   }
 
   RepoCommandResponse&
-  setStartBlockId(uint64_t startBlockId)
-  {
-    m_startBlockId  = startBlockId;
-    m_hasStartBlockId = true;
-    m_wire.reset();
-    return *this;
-  }
+  setStartBlockId(uint64_t startBlockId);
 
   bool
-  hasStartBlockId() const
-  {
-    return m_hasStartBlockId;
-  }
+  hasStartBlockId() const;
 
   uint64_t
   getEndBlockId() const
@@ -96,20 +92,10 @@
   }
 
   RepoCommandResponse&
-  setEndBlockId(uint64_t endBlockId)
-  {
-    m_endBlockId  = endBlockId;
-    m_hasEndBlockId = true;
-    m_wire.reset();
-    return *this;
-  }
+  setEndBlockId(uint64_t endBlockId);
 
   bool
-  hasEndBlockId() const
-  {
-    return m_hasEndBlockId;
-  }
-
+  hasEndBlockId() const;
 
   uint64_t
   getProcessId() const
@@ -118,40 +104,16 @@
   }
 
   RepoCommandResponse&
-  setProcessId(uint64_t processId)
-  {
-    m_processId  = processId;
-    m_hasProcessId = true;
-    m_wire.reset();
-    return *this;
-  }
+  setProcessId(uint64_t processId);
 
   bool
-  hasProcessId() const
-  {
-    return m_hasProcessId;
-  }
-
-  uint64_t
-  getStatusCode() const
-  {
-    return m_statusCode;
-  }
+  hasProcessId() const;
 
   RepoCommandResponse&
-  setStatusCode(uint64_t statusCode)
-  {
-    m_statusCode  = statusCode;
-    m_hasStatusCode = true;
-    m_wire.reset();
-    return *this;
-  }
+  setCode(uint32_t statusCode);
 
   bool
-  hasStatusCode() const
-  {
-    return m_hasStatusCode;
-  }
+  hasStatusCode() const;
 
   uint64_t
   getInsertNum() const
@@ -160,19 +122,10 @@
   }
 
   RepoCommandResponse&
-  setInsertNum(uint64_t insertNum)
-  {
-    m_insertNum = insertNum;
-    m_hasInsertNum = true;
-    m_wire.reset();
-    return *this;
-  }
+  setInsertNum(uint64_t insertNum);
 
   bool
-  hasInsertNum() const
-  {
-    return m_hasInsertNum;
-  }
+  hasInsertNum() const;
 
   uint64_t
   getDeleteNum() const
@@ -181,19 +134,10 @@
   }
 
   RepoCommandResponse&
-  setDeleteNum(uint64_t deleteNum)
-  {
-    m_deleteNum = deleteNum;
-    m_hasDeleteNum = true;
-    m_wire.reset();
-    return *this;
-  }
+  setDeleteNum(uint64_t deleteNum);
 
   bool
-  hasDeleteNum() const
-  {
-    return m_hasDeleteNum;
-  }
+  hasDeleteNum() const;
 
   template<ndn::encoding::Tag T>
   size_t
@@ -206,7 +150,7 @@
   wireDecode(const Block& wire);
 
 private:
-  uint64_t m_statusCode;
+  //uint64_t m_statusCode;
   uint64_t m_startBlockId;
   uint64_t m_endBlockId;
   uint64_t m_processId;
@@ -223,178 +167,7 @@
   mutable Block m_wire;
 };
 
-template<ndn::encoding::Tag T>
-inline size_t
-RepoCommandResponse::wireEncode(EncodingImpl<T>& encoder) const
-{
-  size_t totalLength = 0;
-  size_t variableLength = 0;
-
-  if (m_hasDeleteNum) {
-    variableLength = encoder.prependNonNegativeInteger(m_deleteNum);
-    totalLength += variableLength;
-    totalLength += encoder.prependVarNumber(variableLength);
-    totalLength += encoder.prependVarNumber(tlv::DeleteNum);
-  }
-
-  if (m_hasInsertNum) {
-    variableLength = encoder.prependNonNegativeInteger(m_insertNum);
-    totalLength += variableLength;
-    totalLength += encoder.prependVarNumber(variableLength);
-    totalLength += encoder.prependVarNumber(tlv::InsertNum);
-  }
-
-  if (m_hasEndBlockId) {
-    variableLength = encoder.prependNonNegativeInteger(m_endBlockId);
-    totalLength += variableLength;
-    totalLength += encoder.prependVarNumber(variableLength);
-    totalLength += encoder.prependVarNumber(tlv::EndBlockId);
-  }
-
-  if (m_hasStartBlockId) {
-    variableLength = encoder.prependNonNegativeInteger(m_startBlockId);
-    totalLength += variableLength;
-    totalLength += encoder.prependVarNumber(variableLength);
-    totalLength += encoder.prependVarNumber(repo::tlv::StartBlockId);
-  }
-
-  if (m_hasStatusCode) {
-    variableLength = encoder.prependNonNegativeInteger(m_statusCode);
-    totalLength += variableLength;
-    totalLength += encoder.prependVarNumber(variableLength);
-    totalLength += encoder.prependVarNumber(tlv::StatusCode);
-  }
-  else {
-    BOOST_THROW_EXCEPTION(Error("required field StatusCode is missing"));
-  }
-
-  if (m_hasProcessId) {
-    variableLength = encoder.prependNonNegativeInteger(m_processId);
-    totalLength += variableLength;
-    totalLength += encoder.prependVarNumber(variableLength);
-    totalLength += encoder.prependVarNumber(tlv::ProcessId);
-  }
-
-  totalLength += encoder.prependVarNumber(totalLength);
-  totalLength += encoder.prependVarNumber(tlv::RepoCommandResponse);
-  return totalLength;
-}
-
-inline const Block&
-RepoCommandResponse::wireEncode() const
-{
-  if (m_wire.hasWire())
-    return m_wire;
-
-  EncodingEstimator estimator;
-  size_t estimatedSize = wireEncode(estimator);
-
-  EncodingBuffer buffer(estimatedSize, 0);
-  wireEncode(buffer);
-
-  m_wire = buffer.block();
-  return m_wire;
-}
-
-inline void
-RepoCommandResponse::wireDecode(const Block& wire)
-{
-  m_hasStartBlockId = false;
-  m_hasEndBlockId = false;
-  m_hasProcessId = false;
-  m_hasStatusCode = false;
-  m_hasInsertNum = false;
-  m_hasDeleteNum = false;
-
-  m_wire = wire;
-
-  m_wire.parse();
-
-  Block::element_const_iterator val;
-
-  if (m_wire.type() != tlv::RepoCommandResponse)
-    BOOST_THROW_EXCEPTION(Error("RepoCommandResponse malformed"));
-
-  // StartBlockId
-  val = m_wire.find(tlv::StartBlockId);
-  if (val != m_wire.elements_end())
-  {
-    m_hasStartBlockId = true;
-    m_startBlockId = readNonNegativeInteger(*val);
-  }
-
-  // EndBlockId
-  val = m_wire.find(tlv::EndBlockId);
-  if (val != m_wire.elements_end())
-  {
-    m_hasEndBlockId = true;
-    m_endBlockId = readNonNegativeInteger(*val);
-  }
-
-  // ProcessId
-  val = m_wire.find(tlv::ProcessId);
-  if (val != m_wire.elements_end())
-  {
-    m_hasProcessId = true;
-    m_processId = readNonNegativeInteger(*val);
-  }
-
-  // StatusCode
-  val = m_wire.find(tlv::StatusCode);
-  if (val != m_wire.elements_end())
-  {
-    m_hasStatusCode = true;
-    m_statusCode = readNonNegativeInteger(*val);
-
-  }
-  else {
-    BOOST_THROW_EXCEPTION(Error("required field StatusCode is missing"));
-  }
-
-  // InsertNum
-  val = m_wire.find(tlv::InsertNum);
-  if (val != m_wire.elements_end())
-  {
-    m_hasInsertNum = true;
-    m_insertNum = readNonNegativeInteger(*val);
-  }
-
-  // DeleteNum
-  val = m_wire.find(tlv::DeleteNum);
-  if (val != m_wire.elements_end())
-  {
-    m_hasDeleteNum = true;
-    m_deleteNum = readNonNegativeInteger(*val);
-  }
-}
-
-inline std::ostream&
-operator<<(std::ostream& os, const RepoCommandResponse& repoCommandResponse)
-{
-  os << "RepoCommandResponse(";
-
-  if (repoCommandResponse.hasProcessId()) {
-    os << " ProcessId: " << repoCommandResponse.getProcessId();
-  }
-  if (repoCommandResponse.hasStatusCode()) {
-    os << " StatusCode: " << repoCommandResponse.getStatusCode();
-  }
-  if (repoCommandResponse.hasStartBlockId()) {
-    os << " StartBlockId: " << repoCommandResponse.getStartBlockId();
-  }
-  if (repoCommandResponse.hasEndBlockId()) {
-    os << " EndBlockId: " << repoCommandResponse.getEndBlockId();
-  }
-  if (repoCommandResponse.hasInsertNum()) {
-    os << " InsertNum: " << repoCommandResponse.getInsertNum();
-  }
-  if (repoCommandResponse.hasDeleteNum()) {
-    os << " DeleteNum: " << repoCommandResponse.getDeleteNum();
-
-  }
-  os << " )";
-  return os;
-}
+NDN_CXX_DECLARE_WIRE_ENCODE_INSTANTIATIONS(RepoCommandResponse);
 
 } // namespace repo
 
diff --git a/src/repo-command.cpp b/src/repo-command.cpp
new file mode 100644
index 0000000..b8200d5
--- /dev/null
+++ b/src/repo-command.cpp
@@ -0,0 +1,127 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2018, Regents of the University of California.
+ *
+ * This file is part of NDN repo-ng (Next generation of NDN repository).
+ * See AUTHORS.md for complete list of repo-ng authors and contributors.
+ *
+ * repo-ng 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.
+ *
+ * repo-ng 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
+ * repo-ng, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "repo-command.hpp"
+
+namespace repo {
+
+void
+RepoCommand::validateRequest(const RepoCommandParameter& parameters) {
+  m_requestValidator.validate(parameters);
+  check(parameters);
+}
+
+void
+RepoCommand::FieldValidator::validate(const RepoCommandParameter& parameters) const
+{
+  const std::vector<bool>& presentFields = parameters.getPresentFields();
+
+  for (size_t i = 0; i < REPO_PARAMETER_UBOUND; i++) {
+    bool isPresent = presentFields[i];
+    if (m_required[i]) {
+      if (!isPresent) {
+        BOOST_THROW_EXCEPTION(ArgumentError(REPO_PARAMETER_FIELD[i] + " is required but missing"));
+      }
+    }
+    else if (isPresent && !m_optional[i]) {
+      BOOST_THROW_EXCEPTION(ArgumentError(REPO_PARAMETER_FIELD[i] + " is forbidden but present"));
+    }
+  }
+}
+
+RepoCommand::FieldValidator::FieldValidator()
+  : m_required(REPO_PARAMETER_UBOUND)
+  , m_optional(REPO_PARAMETER_UBOUND)
+{
+}
+
+InsertCommand::InsertCommand()
+: RepoCommand()
+{
+  m_requestValidator
+    .required(REPO_PARAMETER_NAME)
+    .required(REPO_PARAMETER_START_BLOCK_ID)
+    .required(REPO_PARAMETER_END_BLOCK_ID);
+}
+
+InsertCheckCommand::InsertCheckCommand()
+{
+  m_requestValidator
+    .required(REPO_PARAMETER_NAME)
+    .required(REPO_PARAMETER_PROCESS_ID);
+}
+
+WatchStartCommand::WatchStartCommand()
+{
+  m_requestValidator
+    .required(REPO_PARAMETER_NAME)
+    .optional(REPO_PARAMETER_INTEREST_LIFETIME)
+    .optional(REPO_PARAMETER_MAX_INTEREST_NUM)
+    .optional(REPO_PARAMETER_WATCH_TIME_OUT);
+}
+
+WatchCheckCommand::WatchCheckCommand()
+{
+  m_requestValidator
+    .required(REPO_PARAMETER_NAME);
+}
+
+WatchStopCommand::WatchStopCommand()
+{
+  m_requestValidator
+    .required(REPO_PARAMETER_NAME);
+}
+
+DeleteCommand::DeleteCommand()
+{
+  m_requestValidator
+    .required(REPO_PARAMETER_NAME)
+    .required(REPO_PARAMETER_START_BLOCK_ID)
+    .required(REPO_PARAMETER_END_BLOCK_ID)
+    .required(REPO_PARAMETER_PROCESS_ID);
+}
+void
+InsertCommand::check(const RepoCommandParameter& parameters) const
+{
+  if (parameters.hasStartBlockId() || parameters.hasEndBlockId()) {
+    if (parameters.hasSelectors()) {
+      BOOST_THROW_EXCEPTION(ArgumentError("BlockId present. BlockId is not supported in this protocol"));
+      return;
+    }
+  }
+}
+
+void
+DeleteCommand::check(const RepoCommandParameter& parameters) const
+{
+  if (parameters.hasStartBlockId() || parameters.hasEndBlockId()) {
+    if (parameters.hasEndBlockId()) {
+      SegmentNo startBlockId = parameters.getStartBlockId();
+      SegmentNo endBlockId = parameters.getEndBlockId();
+
+      if (startBlockId > endBlockId) {
+        BOOST_THROW_EXCEPTION(ArgumentError("start block Id is bigger than end block Id"));
+      }
+    }
+    else {
+      BOOST_THROW_EXCEPTION(ArgumentError("Segmented deletion without EndBlockId, not implemented"));
+    }
+  }
+}
+} // namespace repo
\ No newline at end of file
diff --git a/src/repo-command.hpp b/src/repo-command.hpp
new file mode 100644
index 0000000..9b1dbe6
--- /dev/null
+++ b/src/repo-command.hpp
@@ -0,0 +1,141 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2018, Regents of the University of California.
+ *
+ * This file is part of NDN repo-ng (Next generation of NDN repository).
+ * See AUTHORS.md for complete list of repo-ng authors and contributors.
+ *
+ * repo-ng 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.
+ *
+ * repo-ng 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
+ * repo-ng, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef REPO_REPO_COMMAND_HPP
+#define REPO_REPO_COMMAND_HPP
+
+#include "common.hpp"
+#include "repo-command-parameter.hpp"
+
+#include <stdexcept>
+
+namespace repo {
+
+class RepoCommand : boost::noncopyable
+{
+public:
+  /** \brief represents an error in RepoCommandParameters
+   */
+  class ArgumentError : public std::invalid_argument
+  {
+  public:
+    explicit
+    ArgumentError(const std::string& what)
+      : std::invalid_argument(what)
+    {
+    }
+  };
+
+  virtual
+  ~RepoCommand() = default;
+
+  class FieldValidator
+  {
+  public:
+    FieldValidator();
+
+    /** \brief declare a required field
+     */
+    FieldValidator&
+    required(RepoParameterField field)
+    {
+      m_required[field] = true;
+      return *this;
+    }
+
+    /** \brief declare an optional field
+     */
+    FieldValidator&
+    optional(RepoParameterField field)
+    {
+      m_optional[field] = true;
+      return *this;
+    }
+
+    /** \brief verify that all required fields are present,
+     *         and all present fields are either required or optional
+     *  \throw ArgumentError
+     */
+    void
+    validate(const RepoCommandParameter& parameters) const;
+
+  private:
+    std::vector<bool> m_required;
+    std::vector<bool> m_optional;
+  };
+
+  void
+  validateRequest(const RepoCommandParameter& parameters);
+
+private:
+  virtual void
+  check(const RepoCommandParameter& parameters) const
+  {
+  }
+
+public:
+  FieldValidator m_requestValidator;
+};
+
+class InsertCommand : public RepoCommand
+{
+public:
+  InsertCommand();
+
+private:
+  void
+  check(const RepoCommandParameter& parameters) const override;
+};
+
+class InsertCheckCommand : public RepoCommand
+{
+public:
+  InsertCheckCommand();
+};
+
+class WatchStartCommand : public RepoCommand
+{
+public:
+  WatchStartCommand();
+};
+
+class WatchCheckCommand : public RepoCommand
+{
+public:
+  WatchCheckCommand();
+};
+
+class WatchStopCommand : public RepoCommand
+{
+public:
+  WatchStopCommand();
+};
+
+class DeleteCommand : public RepoCommand
+{
+public:
+  DeleteCommand();
+
+private:
+  void
+  check(const RepoCommandParameter& parameters) const override;
+};
+
+} // namespace repo
+
+#endif // REPO_REPO_COMMAND_HPP
\ No newline at end of file
diff --git a/src/repo.cpp b/src/repo.cpp
index bb52b45..955db96 100644
--- a/src/repo.cpp
+++ b/src/repo.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017, Regents of the University of California.
+ * Copyright (c) 2014-2018, Regents of the University of California.
  *
  * This file is part of NDN repo-ng (Next generation of NDN repository).
  * See AUTHORS.md for complete list of repo-ng authors and contributors.
@@ -111,15 +111,15 @@
   : m_config(config)
   , m_scheduler(ioService)
   , m_face(ioService)
+  , m_dispatcher(m_face, m_keyChain)
   , m_store(std::make_shared<SqliteStorage>(config.dbPath))
   , m_storageHandle(config.nMaxPackets, *m_store)
   , m_validator(m_face)
-  , m_readHandle(m_face, m_storageHandle, m_keyChain, m_scheduler, m_config.registrationSubset)
-  , m_writeHandle(m_face, m_storageHandle, m_keyChain, m_scheduler, m_validator)
-  , m_watchHandle(m_face, m_storageHandle, m_keyChain, m_scheduler, m_validator)
-  , m_deleteHandle(m_face, m_storageHandle, m_keyChain, m_scheduler, m_validator)
+  , m_readHandle(m_face, m_storageHandle, m_config.registrationSubset)
+  , m_writeHandle(m_face, m_storageHandle, m_dispatcher, m_scheduler, m_validator)
+  , m_watchHandle(m_face, m_storageHandle, m_dispatcher, m_scheduler, m_validator)
+  , m_deleteHandle(m_face, m_storageHandle, m_dispatcher, m_scheduler, m_validator)
   , m_tcpBulkInsertHandle(ioService, m_storageHandle)
-
 {
   this->enableValidation();
 }
@@ -149,9 +149,7 @@
         BOOST_THROW_EXCEPTION(Error("Command prefix registration failed"));
       });
 
-    m_writeHandle.listen(cmdPrefix);
-    m_watchHandle.listen(cmdPrefix);
-    m_deleteHandle.listen(cmdPrefix);
+    m_dispatcher.addTopPrefix(cmdPrefix);
   }
 
   for (const auto& ep : m_config.tcpBulkInsertEndpoints) {
diff --git a/src/repo.hpp b/src/repo.hpp
index 1f29506..e417960 100644
--- a/src/repo.hpp
+++ b/src/repo.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017, Regents of the University of California.
+ * Copyright (c) 2014-2018, Regents of the University of California.
  *
  * This file is part of NDN repo-ng (Next generation of NDN repository).
  * See AUTHORS.md for complete list of repo-ng authors and contributors.
@@ -20,21 +20,22 @@
 #ifndef REPO_REPO_HPP
 #define REPO_REPO_HPP
 
-//#include "storage/repo_storage.hpp"
-#include "storage/sqlite-storage.hpp"
 #include "storage/repo-storage.hpp"
+#include "storage/sqlite-storage.hpp"
 
-#include "handles/read-handle.hpp"
-#include "handles/write-handle.hpp"
-#include "handles/watch-handle.hpp"
 #include "handles/delete-handle.hpp"
+#include "handles/read-handle.hpp"
 #include "handles/tcp-bulk-insert-handle.hpp"
+#include "handles/watch-handle.hpp"
+#include "handles/write-handle.hpp"
 
 #include "common.hpp"
 
+#include <ndn-cxx/mgmt/dispatcher.hpp>
 #include <ndn-cxx/security/validator-config.hpp>
-#include <boost/property_tree/ptree.hpp>
+
 #include <boost/property_tree/info_parser.hpp>
+#include <boost/property_tree/ptree.hpp>
 
 namespace repo {
 
@@ -86,10 +87,12 @@
   RepoConfig m_config;
   ndn::Scheduler m_scheduler;
   ndn::Face m_face;
+  ndn::mgmt::Dispatcher m_dispatcher;
   std::shared_ptr<Storage> m_store;
   RepoStorage m_storageHandle;
   KeyChain m_keyChain;
   ValidatorConfig m_validator;
+
   ReadHandle m_readHandle;
   WriteHandle m_writeHandle;
   WatchHandle m_watchHandle;
diff --git a/src/storage/storage.hpp b/src/storage/storage.hpp
index e1cb537..5286c8a 100755
--- a/src/storage/storage.hpp
+++ b/src/storage/storage.hpp
@@ -21,6 +21,9 @@
 #define REPO_STORAGE_STORAGE_HPP
 
 #include "../common.hpp"
+#include <string>
+#include <iostream>
+#include <stdlib.h>
 
 namespace repo {
 
diff --git a/tests/dataset-fixtures.hpp b/tests/dataset-fixtures.hpp
index fbed46d..bb03bd6 100644
--- a/tests/dataset-fixtures.hpp
+++ b/tests/dataset-fixtures.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2017, Regents of the University of California.
+ * Copyright (c) 2014-2018, Regents of the University of California.
  *
  * This file is part of NDN repo-ng (Next generation of NDN repository).
  * See AUTHORS.md for complete list of repo-ng authors and contributors.
@@ -378,12 +378,12 @@
 };
 
 
-typedef boost::mpl::vector< BasicDataset,
-                            FetchByPrefixDataset,
-                            BasicChildSelectorDataset,
-                            ExtendedChildSelectorDataset,
-                            SamePrefixDataset<10>,
-                            SamePrefixDataset<100> > CommonDatasets;
+typedef boost::mpl::vector<BasicDataset,
+                           FetchByPrefixDataset,
+                           BasicChildSelectorDataset,
+                           ExtendedChildSelectorDataset,
+                           SamePrefixDataset<10>,
+                           SamePrefixDataset<100>> CommonDatasets;
 
 
 } // namespace tests
diff --git a/tests/integrated/command-fixture.cpp b/tests/integrated/command-fixture.cpp
index 1680dad..a803a51 100644
--- a/tests/integrated/command-fixture.cpp
+++ b/tests/integrated/command-fixture.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017, Regents of the University of California.
+ * Copyright (c) 2014-2018, Regents of the University of California.
  *
  * This file is part of NDN repo-ng (Next generation of NDN repository).
  * See AUTHORS.md for complete list of repo-ng authors and contributors.
@@ -25,6 +25,7 @@
 CommandFixture::CommandFixture()
   : scheduler(repoFace.getIoService())
   , keyChain(m_keyChain)
+  , dispatcher(repoFace, keyChain)
   , validator(repoFace)
 {
   this->saveIdentityCertificate(keyChain.getPib().getDefaultIdentity().getName(),
diff --git a/tests/integrated/command-fixture.hpp b/tests/integrated/command-fixture.hpp
index fa2fdd9..601f0b9 100644
--- a/tests/integrated/command-fixture.hpp
+++ b/tests/integrated/command-fixture.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017, Regents of the University of California.
+ * Copyright (c) 2014-2018, Regents of the University of California.
  *
  * This file is part of NDN repo-ng (Next generation of NDN repository).
  * See AUTHORS.md for complete list of repo-ng authors and contributors.
@@ -22,6 +22,7 @@
 
 #include "../identity-management-fixture.hpp"
 #include <ndn-cxx/security/validator-null.hpp>
+#include <ndn-cxx/mgmt/dispatcher.hpp>
 
 namespace repo {
 namespace tests {
@@ -35,7 +36,7 @@
   Face repoFace;
   Scheduler scheduler;
   KeyChain& keyChain;
-
+  ndn::mgmt::Dispatcher dispatcher;
   /// \todo #4091 switch to ValidatorPolicyConf and load insert-delete-validator-config.conf
   ValidatorConfig validator;
 };
diff --git a/tests/integrated/insert-delete-validator-config.conf b/tests/integrated/insert-delete-validator-config.conf
index 8a777c5..c97bb4c 100644
--- a/tests/integrated/insert-delete-validator-config.conf
+++ b/tests/integrated/insert-delete-validator-config.conf
@@ -15,19 +15,20 @@
   }
   checker
   {
-    type fixed-signer
+    type customized
     sig-type rsa-sha256
-    signer
+    key-locator
     {
-      type file
-      file-name "insert-delete-test.cert"
+      type name
+      name /DEFAULT
+      relation equal
     }
   }
 }
 
 rule
 {
-  id "Test Rule For Datat"
+  id "Test Rule For Data"
   for data
   filter
   {
@@ -37,12 +38,19 @@
   }
   checker
   {
-    type fixed-signer
+    type customized
     sig-type rsa-sha256
-    signer
+    key-locator
     {
-      type file
-      file-name "insert-delete-test.cert"
+      type name
+      name /DEFAULT
+      relation equal
     }
   }
-}
\ No newline at end of file
+}
+
+trust-anchor
+{
+  type file
+  file-name "insert-delete-test.cert"
+}
diff --git a/tests/integrated/test-basic-command-insert-delete.cpp b/tests/integrated/test-basic-command-insert-delete.cpp
index ff4b866..ea58abe 100644
--- a/tests/integrated/test-basic-command-insert-delete.cpp
+++ b/tests/integrated/test-basic-command-insert-delete.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017, Regents of the University of California.
+ * Copyright (c) 2014-2018, Regents of the University of California.
  *
  * This file is part of NDN repo-ng (Next generation of NDN repository).
  * See AUTHORS.md for complete list of repo-ng authors and contributors.
@@ -17,20 +17,28 @@
  * repo-ng, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "handles/write-handle.hpp"
 #include "handles/delete-handle.hpp"
-#include "storage/sqlite-storage.hpp"
+#include "handles/write-handle.hpp"
+
 #include "storage/repo-storage.hpp"
+#include "storage/sqlite-storage.hpp"
 
 #include "command-fixture.hpp"
 #include "../repo-storage-fixture.hpp"
 #include "../dataset-fixtures.hpp"
 
+#include <ndn-cxx/security/command-interest-signer.hpp>
+#include <ndn-cxx/security/signing-helpers.hpp>
 #include <ndn-cxx/util/random.hpp>
+#include <ndn-cxx/util/time.hpp>
 
+#include <boost/asio/io_service.hpp>
 #include <boost/mpl/vector.hpp>
 #include <boost/test/unit_test.hpp>
 
+
+#include <iostream>
+
 namespace repo {
 namespace tests {
 
@@ -48,8 +56,8 @@
 {
 public:
   Fixture()
-    : writeHandle(repoFace, *handle, keyChain, scheduler, validator)
-    , deleteHandle(repoFace, *handle, keyChain, scheduler, validator)
+    : writeHandle(repoFace, *handle, dispatcher, scheduler, validator)
+    , deleteHandle(repoFace, *handle, dispatcher, scheduler, validator)
     , insertFace(repoFace.getIoService())
     , deleteFace(repoFace.getIoService())
   {
@@ -58,8 +66,6 @@
       [] (const Name& cmdPrefix, const std::string& reason) {
         BOOST_FAIL("Command prefix registration error: " << reason);
       });
-    writeHandle.listen(cmdPrefix);
-    deleteHandle.listen(cmdPrefix);
   }
 
   void
@@ -114,7 +120,7 @@
 {
   Data data(Name(interest.getName()));
   data.setContent(content, sizeof(content));
-  data.setFreshnessPeriod(milliseconds(0));
+  data.setFreshnessPeriod(0_ms);
   keyChain.sign(data);
   insertFace.put(data);
   std::map<Name, EventId>::iterator event = insertEvents.find(interest.getName());
@@ -123,7 +129,7 @@
     insertEvents.erase(event);
   }
   // schedule an event 50ms later to check whether insert is Ok
-  scheduler.scheduleEvent(milliseconds(500),
+  scheduler.scheduleEvent(500_ms,
                           bind(&Fixture<T>::checkInsertOk, this, interest));
 
 }
@@ -146,9 +152,8 @@
 {
   RepoCommandResponse response;
   response.wireDecode(data.getContent().blockFromValue());
-  int statusCode = response.getStatusCode();
+  int statusCode = response.getCode();
   BOOST_CHECK_EQUAL(statusCode, 100);
-  //  std::cout<<"statuse code of insert name = "<<response.getName()<<std::endl;
 }
 
 template<class T> void
@@ -156,11 +161,11 @@
 {
   RepoCommandResponse response;
   response.wireDecode(data.getContent().blockFromValue());
-  int statusCode = response.getStatusCode();
+  int statusCode = response.getCode();
   BOOST_CHECK_EQUAL(statusCode, 200);
 
   //schedlute an event to check whether delete is Ok.
-  scheduler.scheduleEvent(milliseconds(100),
+  scheduler.scheduleEvent(100_ms,
                           bind(&Fixture<T>::checkDeleteOk, this, interest));
 }
 
@@ -204,7 +209,7 @@
     BOOST_CHECK_EQUAL(rc, 0);
   }
   else {
-    std::cerr<<"Check Insert Failed"<<std::endl;
+    BOOST_ERROR("Check Insert Failed");
   }
 }
 
@@ -229,11 +234,11 @@
     insertCommandName.append(insertParameter.wireEncode());
     Interest insertInterest(insertCommandName);
     keyChain.sign(insertInterest);
-    //schedule a job to express insertInterest every 50ms
+
+    // schedule a job to express insertInterest every 50ms
     scheduler.scheduleEvent(milliseconds(timeCount * 50 + 1000),
                             bind(&Fixture<T>::sendInsertInterest, this, insertInterest));
-    //schedule what to do when interest timeout
-
+    // schedule what to do when interest timeout
     EventId delayEventId = scheduler.scheduleEvent(milliseconds(5000 + timeCount * 50),
                                                    bind(&Fixture<T>::delayedInterest, this));
     insertEvents[insertParameter.getName()] = delayEventId;
@@ -266,21 +271,21 @@
   }
 }
 
-typedef boost::mpl::vector< BasicDataset,
-                            FetchByPrefixDataset,
-                            BasicChildSelectorDataset,
-                            ExtendedChildSelectorDataset,
-                            SamePrefixDataset<10> > Datasets;
+typedef boost::mpl::vector<BasicDataset,
+                           FetchByPrefixDataset,
+                           BasicChildSelectorDataset,
+                           ExtendedChildSelectorDataset,
+                           SamePrefixDataset<10>> Datasets;
 
 BOOST_FIXTURE_TEST_CASE_TEMPLATE(InsertDelete, T, Datasets, Fixture<T>)
 {
   // schedule events
-  this->scheduler.scheduleEvent(seconds(0),
+  this->scheduler.scheduleEvent(0_s,
                                 bind(&Fixture<T>::scheduleInsertEvent, this));
-  this->scheduler.scheduleEvent(seconds(10),
+  this->scheduler.scheduleEvent(10_s,
                                 bind(&Fixture<T>::scheduleDeleteEvent, this));
 
-  this->repoFace.processEvents(seconds(30));
+  this->repoFace.processEvents(30_s);
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/integrated/test-basic-command-watch.cpp b/tests/integrated/test-basic-command-watch.cpp
index 1e38da9..6fe677d 100644
--- a/tests/integrated/test-basic-command-watch.cpp
+++ b/tests/integrated/test-basic-command-watch.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017, Regents of the University of California.
+ * Copyright (c) 2014-2018, Regents of the University of California.
  *
  * This file is part of NDN repo-ng (Next generation of NDN repository).
  * See AUTHORS.md for complete list of repo-ng authors and contributors.
@@ -46,7 +46,7 @@
 {
 public:
   Fixture()
-    : watchHandle(repoFace, *handle, keyChain, scheduler, validator)
+    : watchHandle(repoFace, *handle, dispatcher, scheduler, validator)
     , watchFace(repoFace.getIoService())
   {
     Name cmdPrefix("/repo/command");
@@ -54,7 +54,6 @@
       [] (const Name& cmdPrefix, const std::string& reason) {
         BOOST_FAIL("Command prefix registration error: " << reason);
       });
-    watchHandle.listen(cmdPrefix);
   }
 
   void
@@ -99,12 +98,12 @@
   auto data = make_shared<Data>(Name(interest.getName())
                                 .appendNumber(ndn::random::generateWord64() + 100));
   data->setContent(content, sizeof(content));
-  data->setFreshnessPeriod(milliseconds(0));
+  data->setFreshnessPeriod(0_ms);
   keyChain.sign(*data);
   watchFace.put(*data);
 
   // schedule an event 50ms later to check whether watch is Ok
-  scheduler.scheduleEvent(milliseconds(10000),
+  scheduler.scheduleEvent(10000_ms,
                           bind(&Fixture<T>::checkWatchOk, this,
                                Interest(data->getName())));
 }
@@ -128,7 +127,7 @@
   RepoCommandResponse response;
   response.wireDecode(data.getContent().blockFromValue());
 
-  int statusCode = response.getStatusCode();
+  int statusCode = response.getCode();
   BOOST_CHECK_EQUAL(statusCode, 100);
 }
 
@@ -138,7 +137,7 @@
   RepoCommandResponse response;
   response.wireDecode(data.getContent().blockFromValue());
 
-  int statusCode = response.getStatusCode();
+  int statusCode = response.getCode();
   BOOST_CHECK_EQUAL(statusCode, 101);
 }
 
@@ -187,13 +186,13 @@
   RepoCommandParameter watchParameter;
   watchParameter.setName(Name("/a/b"));
   watchParameter.setMaxInterestNum(10);
-  watchParameter.setInterestLifetime(milliseconds(50000));
-  watchParameter.setWatchTimeout(milliseconds(1000000000));
+  watchParameter.setInterestLifetime(50000_ms);
+  watchParameter.setWatchTimeout(1000000000_ms);
   watchCommandName.append(watchParameter.wireEncode());
   Interest watchInterest(watchCommandName);
   keyChain.sign(watchInterest);
   //schedule a job to express watchInterest
-  scheduler.scheduleEvent(milliseconds(1000),
+  scheduler.scheduleEvent(1000_ms,
                           bind(&Fixture<T>::sendWatchStartInterest, this, watchInterest));
 
   Name watchStopName("/repo/command/watch/stop");
@@ -202,8 +201,6 @@
   Interest watchStopInterest(watchStopName);
   keyChain.sign(watchStopInterest);
 
- // scheduler.scheduleEvent(milliseconds(10000),
-  //                        bind(&Fixture<T>::sendWatchStopInterest, this, watchStopInterest));
   //The delayEvent will be canceled in onWatchInterest
   watchFace.setInterestFilter(watchParameter.getName(),
                               bind(&Fixture<T>::onWatchInterest, this, _2),
@@ -211,15 +208,15 @@
                               bind(&Fixture<T>::onRegisterFailed, this, _2));
 }
 
-typedef boost::mpl::vector< BasicDataset > Dataset;
+typedef boost::mpl::vector<BasicDataset> Dataset;
 
 BOOST_FIXTURE_TEST_CASE_TEMPLATE(WatchDelete, T, Dataset, Fixture<T>)
 {
   // schedule events
-  this->scheduler.scheduleEvent(seconds(0),
+  this->scheduler.scheduleEvent(1_s,
                                 bind(&Fixture<T>::scheduleWatchEvent, this));
 
-  this->repoFace.processEvents(seconds(500));
+  this->repoFace.processEvents(500_s);
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/integrated/test-basic-interest-read.cpp b/tests/integrated/test-basic-interest-read.cpp
index 8028894..0ad2f3c 100644
--- a/tests/integrated/test-basic-interest-read.cpp
+++ b/tests/integrated/test-basic-interest-read.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017, Regents of the University of California.
+ * Copyright (c) 2014-2018, Regents of the University of California.
  *
  * This file is part of NDN repo-ng (Next generation of NDN repository).
  * See AUTHORS.md for complete list of repo-ng authors and contributors.
@@ -27,6 +27,8 @@
 #include <boost/asio/io_service.hpp>
 #include <boost/test/unit_test.hpp>
 
+#include <ndn-cxx/util/time.hpp>
+
 namespace repo {
 namespace tests {
 
@@ -41,7 +43,7 @@
 public:
   BasicInterestReadFixture()
     : scheduler(repoFace.getIoService())
-    , readHandle(repoFace, *handle, keyChain, scheduler, 0)
+    , readHandle(repoFace, *handle, 0)
     , readFace(repoFace.getIoService())
   {
   }
@@ -65,7 +67,7 @@
          i != this->data.end(); ++i) {
       //First insert a data into database;
       (*i)->setContent(content, sizeof(content));
-      (*i)->setFreshnessPeriod(ndn::time::milliseconds(36000));
+      (*i)->setFreshnessPeriod(36000_ms);
       keyChain.sign(**i);
       bool rc = handle->insertData(**i);
 
@@ -93,11 +95,17 @@
   }
 
   void
+  onReadNack(const ndn::Interest& interest, const ndn::lp::Nack& nack)
+  {
+    BOOST_ERROR("Read nacked");
+  }
+
+  void
   sendInterest(const ndn::Interest& interest)
   {
     readFace.expressInterest(interest,
                              bind(&BasicInterestReadFixture::onReadData, this, _1, _2),
-                             bind(&BasicInterestReadFixture::onReadTimeout, this, _1), // Nack
+                             bind(&BasicInterestReadFixture::onReadNack, this, _1, _2),
                              bind(&BasicInterestReadFixture::onReadTimeout, this, _1));
   }
 
@@ -109,28 +117,19 @@
   ndn::Face readFace;
 };
 
-
-typedef boost::mpl::vector< BasicDataset,
+typedef boost::mpl::vector<BasicDataset,
                             FetchByPrefixDataset,
                             BasicChildSelectorDataset,
                             ExtendedChildSelectorDataset,
-                            SamePrefixDataset<10> > Datasets;
+                            SamePrefixDataset<10>> Datasets;
 
 BOOST_FIXTURE_TEST_CASE_TEMPLATE(Read, T, Datasets, BasicInterestReadFixture<T>)
 {
-  // Insert dataset
-  // for (typename T::DataContainer::iterator i = this->data.begin();
-  //      i != this->data.end(); ++i) {
-  //   BOOST_CHECK_EQUAL(this->handle.insertData(**i), true);
-  // }
-
-  // BOOST_CHECK_EQUAL(this->handle.size(), this->data.size());
-
   this->startListen();
-  this->scheduler.scheduleEvent(ndn::time::seconds(0),
+  this->scheduler.scheduleEvent(1_s,
                                 bind(&BasicInterestReadFixture<T>::scheduleReadEvent, this));
 
-  this->repoFace.processEvents(ndn::time::seconds(20));
+  this->repoFace.processEvents(20_s);
 
 }
 
diff --git a/tests/unit/read-handle.t.cpp b/tests/unit/read-handle.t.cpp
index cb9d233..9afc325 100644
--- a/tests/unit/read-handle.t.cpp
+++ b/tests/unit/read-handle.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2017,  Regents of the University of California.
+ * Copyright (c) 2014-2018,  Regents of the University of California.
  *
  * This file is part of NDN repo-ng (Next generation of NDN repository).
  * See AUTHORS.md for complete list of repo-ng authors and contributors.
@@ -53,7 +53,7 @@
     , subsetLength(1)
     , dataPrefix("/ndn/test/prefix")
     , identity("/ndn/test/identity")
-    , readHandle(face, *handle, keyChain, scheduler, subsetLength)
+    , readHandle(face, *handle, subsetLength)
     , numPrefixRegistrations(0)
     , numPrefixUnregistrations(0)
   {
@@ -103,32 +103,32 @@
   bool didMatch = false;
   face.sentInterests.clear();
   handle->insertData(*data1);
-  face.processEvents(ndn::time::milliseconds(-1));
+  face.processEvents(-1_ms);
   CHECK_INTERESTS(interest.getName(), name::Component{"register"}, true);
 
   face.sentInterests.clear();
   handle->deleteData(data1->getFullName());
-  face.processEvents(ndn::time::milliseconds(-1));
+  face.processEvents(-1_ms);
   CHECK_INTERESTS(interest.getName(), name::Component{"unregister"}, true);
 
   face.sentInterests.clear();
   handle->insertData(*data1);
-  face.processEvents(ndn::time::milliseconds(-1));
+  face.processEvents(-1_ms);
   CHECK_INTERESTS(interest.getName(), name::Component{"register"}, true);
 
   face.sentInterests.clear();
   handle->insertData(*data2);
-  face.processEvents(ndn::time::milliseconds(-1));
+  face.processEvents(-1_ms);
   CHECK_INTERESTS(interest.getName(), name::Component{"register"}, false);
 
   face.sentInterests.clear();
   handle->deleteData(data1->getFullName());
-  face.processEvents(ndn::time::milliseconds(-1));
+  face.processEvents(-1_ms);
   CHECK_INTERESTS(interest.getName(), name::Component{"unregister"}, false);
 
   face.sentInterests.clear();
   handle->deleteData(data2->getFullName());
-  face.processEvents(ndn::time::milliseconds(-1));
+  face.processEvents(-1_ms);
   CHECK_INTERESTS(interest.getName(), name::Component{"unregister"}, true);
 }
 
diff --git a/tests/unit/repo-command-response.cpp b/tests/unit/repo-command-response.cpp
index ab03207..7686c50 100644
--- a/tests/unit/repo-command-response.cpp
+++ b/tests/unit/repo-command-response.cpp
@@ -29,7 +29,7 @@
 BOOST_AUTO_TEST_CASE(EncodeDecode)
 {
   repo::RepoCommandResponse response;
-  response.setStatusCode(404);
+  response.setCode(404);
   response.setStartBlockId(1);
   response.setEndBlockId(100);
   response.setProcessId(1234567890);
@@ -53,7 +53,7 @@
                                   wire.begin(), wire.end());
 
   repo::RepoCommandResponse decoded(wire);
-  BOOST_CHECK_EQUAL(decoded.getStatusCode(), response.getStatusCode());
+  BOOST_CHECK_EQUAL(decoded.getCode(), response.getCode());
   BOOST_CHECK_EQUAL(decoded.getStartBlockId(), response.getStartBlockId());
   BOOST_CHECK_EQUAL(decoded.getEndBlockId(), response.getEndBlockId());
   BOOST_CHECK_EQUAL(decoded.getProcessId(), response.getProcessId());
diff --git a/tools/ndngetfile.cpp b/tools/ndngetfile.cpp
index 4d26763..9764ca6 100644
--- a/tools/ndngetfile.cpp
+++ b/tools/ndngetfile.cpp
@@ -187,8 +187,9 @@
   if (m_retryCount++ < MAX_RETRY) {
     // Retransmit the interest
     fetchData(interest.getName());
-    if (m_verbose)
-      std::cerr << "TIMEOUT: retransmit interest for " << interest.getName() << std::endl;
+    if (m_verbose) {
+        std::cerr << "TIMEOUT: retransmit interest for " << interest.getName() << std::endl;
+    }
   }
   else {
     std::cerr << "TIMEOUT: last interest sent for segment #" << (m_nextSegment - 1) << std::endl;
@@ -225,48 +226,50 @@
   int opt;
   while ((opt = getopt(argc, argv, "vsul:w:o:")) != -1) {
     switch (opt) {
-    case 'v':
-      verbose = true;
-      break;
-    case 's':
-      single = true;
-      break;
-    case 'u':
-      versioned = true;
-      break;
-    case 'l':
-      try {
-        interestLifetime = boost::lexical_cast<int>(optarg);
-      }
-      catch (const boost::bad_lexical_cast&) {
-        std::cerr << "ERROR: -l option should be an integer." << std::endl;
-        return 1;
-      }
-      interestLifetime = std::max(interestLifetime, 0);
-      break;
-    case 'w':
-      try {
-        timeout = boost::lexical_cast<int>(optarg);
-      }
-      catch (const boost::bad_lexical_cast&) {
-        std::cerr << "ERROR: -w option should be an integer." << std::endl;
-        return 1;
-      }
-      timeout = std::max(timeout, 0);
-      break;
-    case 'o':
-      outputFile = optarg;
-      break;
-    default:
-      return usage(argv[0]);
+      case 'v':
+        verbose = true;
+        break;
+      case 's':
+        single = true;
+        break;
+      case 'u':
+        versioned = true;
+        break;
+      case 'l':
+        try {
+          interestLifetime = boost::lexical_cast<int>(optarg);
+        }
+        catch (const boost::bad_lexical_cast&) {
+          std::cerr << "ERROR: -l option should be an integer." << std::endl;
+          return 1;
+        }
+        interestLifetime = std::max(interestLifetime, 0);
+        break;
+      case 'w':
+        try {
+          timeout = boost::lexical_cast<int>(optarg);
+        }
+        catch (const boost::bad_lexical_cast&) {
+          std::cerr << "ERROR: -w option should be an integer." << std::endl;
+          return 1;
+        }
+        timeout = std::max(timeout, 0);
+        break;
+      case 'o':
+        outputFile = optarg;
+        break;
+      default:
+        return usage(argv[0]);
     }
   }
 
-  if (optind < argc)
+  if (optind < argc) {
     name = argv[optind];
+  }
 
-  if (name.empty())
+  if (name.empty()) {
     return usage(argv[0]);
+  }
 
   std::streambuf* buf;
   std::ofstream of;
diff --git a/tools/ndnputfile.cpp b/tools/ndnputfile.cpp
index 583d478..b4f40f4 100644
--- a/tools/ndnputfile.cpp
+++ b/tools/ndnputfile.cpp
@@ -265,7 +265,8 @@
 NdnPutFile::onInsertCommandResponse(const ndn::Interest& interest, const ndn::Data& data)
 {
   RepoCommandResponse response(data.getContent().blockFromValue());
-  int statusCode = response.getStatusCode();
+  //int statusCode = response.getStatusCode();
+  int statusCode = response.getCode();
   if (statusCode >= 400) {
     BOOST_THROW_EXCEPTION(Error("insert command failed with code " +
                                 boost::lexical_cast<std::string>(statusCode)));
@@ -397,7 +398,7 @@
 NdnPutFile::onCheckCommandResponse(const ndn::Interest& interest, const ndn::Data& data)
 {
   RepoCommandResponse response(data.getContent().blockFromValue());
-  int statusCode = response.getStatusCode();
+  int statusCode = response.getCode();
   if (statusCode >= 400) {
     BOOST_THROW_EXCEPTION(Error("Insert check command failed with code: " +
                                 boost::lexical_cast<std::string>(statusCode)));
@@ -542,8 +543,8 @@
   if (argc != 3)
     usage();
 
-  ndnPutFile.repoPrefix = Name(argv[0]);
-  ndnPutFile.ndnName = Name(argv[1]);
+  ndnPutFile.repoPrefix = Name(argv[0]); std::cout << "Repo prefix: " << argv[0] << std::endl;
+  ndnPutFile.ndnName = Name(argv[1]);    std::cout << "NDN name: " << argv[1] << std::endl;
   if (strcmp(argv[2], "-") == 0) {
 
     ndnPutFile.insertStream = &std::cin;
diff --git a/tools/ndnrepowatch.cpp b/tools/ndnrepowatch.cpp
index 0707c87..b844c00 100644
--- a/tools/ndnrepowatch.cpp
+++ b/tools/ndnrepowatch.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017, Regents of the University of California.
+ * Copyright (c) 2014-2018, Regents of the University of California.
  *
  * This file is part of NDN repo-ng (Next generation of NDN repository).
  * See AUTHORS.md for complete list of repo-ng authors and contributors.
@@ -24,6 +24,8 @@
 #include <ndn-cxx/security/command-interest-signer.hpp>
 #include <ndn-cxx/security/key-chain.hpp>
 #include <ndn-cxx/security/signing-helpers.hpp>
+
+#include <boost/asio/io_service.hpp>
 #include <ndn-cxx/util/scheduler.hpp>
 
 #include <stdint.h>
@@ -201,7 +203,7 @@
 NdnRepoWatch::onWatchCommandResponse(const ndn::Interest& interest, const ndn::Data& data)
 {
   RepoCommandResponse response(data.getContent().blockFromValue());
-  int statusCode = response.getStatusCode();
+  int statusCode = response.getCode();
   if (statusCode >= 400) {
     BOOST_THROW_EXCEPTION(Error("Watch command failed with code " +
                                 boost::lexical_cast<std::string>(statusCode)));
@@ -264,7 +266,7 @@
 NdnRepoWatch::onStopCommandResponse(const ndn::Interest& interest, ndn::Data& data)
 {
   RepoCommandResponse response(data.getContent().blockFromValue());
-  int statusCode = response.getStatusCode();
+  int statusCode = response.getCode();
   if (statusCode != 101) {
     BOOST_THROW_EXCEPTION(Error("Watch stop command failed with code: " +
                                 boost::lexical_cast<std::string>(statusCode)));
diff --git a/tools/wscript b/tools/wscript
index aadf3a4..0a9fcbf 100644
--- a/tools/wscript
+++ b/tools/wscript
@@ -8,6 +8,6 @@
             bld(features=['cxx', 'cxxprogram'],
                 target='%s' % (str(app.change_ext('', '.cpp'))),
                 source=app,
-                use='NDN_CXX',
+                use=["NDN_CXX", "ndn-repo-objects"],
                 includes="../src",
                 )