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 {