management: avoid CommandInterestGenerator in nfd::Controller

refs #1849

Change-Id: Id416c0e33100312b9877f5e45db6a7a3651df961
diff --git a/src/management/nfd-control-command.cpp b/src/management/nfd-control-command.cpp
new file mode 100644
index 0000000..ac7a40d
--- /dev/null
+++ b/src/management/nfd-control-command.cpp
@@ -0,0 +1,357 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "nfd-control-command.hpp"
+
+namespace ndn {
+namespace nfd {
+
+ControlCommand::ControlCommand(const std::string& module, const std::string& verb)
+  : m_prefix("ndn:/localhost/nfd")
+{
+  m_prefix.append(module).append(verb);
+}
+
+void
+ControlCommand::validateRequest(const ControlParameters& parameters) const
+{
+  m_requestValidator.validate(parameters);
+}
+
+void
+ControlCommand::applyDefaultsToRequest(ControlParameters& parameters) const
+{
+}
+
+void
+ControlCommand::validateResponse(const ControlParameters& parameters) const
+{
+  m_responseValidator.validate(parameters);
+}
+
+void
+ControlCommand::applyDefaultsToResponse(ControlParameters& parameters) const
+{
+}
+
+Name
+ControlCommand::getRequestName(const ControlParameters& parameters) const
+{
+  this->validateRequest(parameters);
+
+  Name name = m_prefix;
+  name.append(parameters.wireEncode());
+  return name;
+}
+
+Interest
+ControlCommand::makeCommandInterest(const ControlParameters& parameters,
+                                    const Sign& sign) const
+{
+  Interest commandInterest(this->getRequestName(parameters));
+  sign(commandInterest);
+  return commandInterest;
+}
+
+ControlCommand::FieldValidator::FieldValidator()
+  : m_required(CONTROL_PARAMETER_UBOUND)
+  , m_optional(CONTROL_PARAMETER_UBOUND)
+{
+}
+
+void
+ControlCommand::FieldValidator::validate(const ControlParameters& parameters) const
+{
+  const std::vector<bool>& presentFields = parameters.getPresentFields();
+
+  for (size_t i = 0; i < CONTROL_PARAMETER_UBOUND; ++i) {
+    bool isPresent = presentFields[i];
+    if (m_required[i]) {
+      if (!isPresent) {
+        throw ArgumentError(CONTROL_PARAMETER_FIELD[i] + " is required but missing");
+      }
+    }
+    else if (isPresent && !m_optional[i]) {
+      throw ArgumentError(CONTROL_PARAMETER_FIELD[i] + " is forbidden but present");
+    }
+  }
+}
+
+FaceCreateCommand::FaceCreateCommand()
+  : ControlCommand("faces", "create")
+{
+  m_requestValidator
+    .required(CONTROL_PARAMETER_URI);
+  m_responseValidator
+    .required(CONTROL_PARAMETER_URI)
+    .required(CONTROL_PARAMETER_FACE_ID);
+}
+
+void
+FaceCreateCommand::validateResponse(const ControlParameters& parameters) const
+{
+  this->ControlCommand::validateResponse(parameters);
+
+  if (parameters.getFaceId() == 0) {
+    throw ArgumentError("FaceId must not be zero");
+  }
+}
+
+FaceDestroyCommand::FaceDestroyCommand()
+  : ControlCommand("faces", "destroy")
+{
+  m_requestValidator
+    .required(CONTROL_PARAMETER_FACE_ID);
+  m_responseValidator = m_requestValidator;
+}
+
+void
+FaceDestroyCommand::validateRequest(const ControlParameters& parameters) const
+{
+  this->ControlCommand::validateRequest(parameters);
+
+  if (parameters.getFaceId() == 0) {
+    throw ArgumentError("FaceId must not be zero");
+  }
+}
+
+void
+FaceDestroyCommand::validateResponse(const ControlParameters& parameters) const
+{
+  this->validateRequest(parameters);
+}
+
+FaceLocalControlCommand::FaceLocalControlCommand(const std::string& verb)
+  : ControlCommand("faces", verb)
+{
+  m_requestValidator
+    .required(CONTROL_PARAMETER_LOCAL_CONTROL_FEATURE);
+  m_responseValidator = m_requestValidator;
+}
+
+void
+FaceLocalControlCommand::validateRequest(const ControlParameters& parameters) const
+{
+  this->ControlCommand::validateRequest(parameters);
+
+  switch (parameters.getLocalControlFeature()) {
+    case LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID:
+    case LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID:
+      break;
+    default:
+      throw ArgumentError("LocalControlFeature is invalid");
+  }
+}
+
+void
+FaceLocalControlCommand::validateResponse(const ControlParameters& parameters) const
+{
+  this->validateRequest(parameters);
+}
+
+FaceEnableLocalControlCommand::FaceEnableLocalControlCommand()
+  : FaceLocalControlCommand("enable-local-control")
+{
+}
+
+FaceDisableLocalControlCommand::FaceDisableLocalControlCommand()
+  : FaceLocalControlCommand("disable-local-control")
+{
+}
+
+FibAddNextHopCommand::FibAddNextHopCommand()
+  : ControlCommand("fib", "add-nexthop")
+{
+  m_requestValidator
+    .required(CONTROL_PARAMETER_NAME)
+    .optional(CONTROL_PARAMETER_FACE_ID)
+    .optional(CONTROL_PARAMETER_COST);
+  m_responseValidator
+    .required(CONTROL_PARAMETER_NAME)
+    .required(CONTROL_PARAMETER_FACE_ID)
+    .required(CONTROL_PARAMETER_COST);
+}
+
+void
+FibAddNextHopCommand::applyDefaultsToRequest(ControlParameters& parameters) const
+{
+  if (!parameters.hasFaceId()) {
+    parameters.setFaceId(0);
+  }
+  if (!parameters.hasCost()) {
+    parameters.setCost(0);
+  }
+}
+
+void
+FibAddNextHopCommand::validateResponse(const ControlParameters& parameters) const
+{
+  this->ControlCommand::validateResponse(parameters);
+
+  if (parameters.getFaceId() == 0) {
+    throw ArgumentError("FaceId must not be zero");
+  }
+}
+
+FibRemoveNextHopCommand::FibRemoveNextHopCommand()
+  : ControlCommand("fib", "remove-nexthop")
+{
+  m_requestValidator
+    .required(CONTROL_PARAMETER_NAME)
+    .optional(CONTROL_PARAMETER_FACE_ID);
+  m_responseValidator
+    .required(CONTROL_PARAMETER_NAME)
+    .required(CONTROL_PARAMETER_FACE_ID);
+}
+
+void
+FibRemoveNextHopCommand::applyDefaultsToRequest(ControlParameters& parameters) const
+{
+  if (!parameters.hasFaceId()) {
+    parameters.setFaceId(0);
+  }
+}
+
+void
+FibRemoveNextHopCommand::validateResponse(const ControlParameters& parameters) const
+{
+  this->ControlCommand::validateResponse(parameters);
+
+  if (parameters.getFaceId() == 0) {
+    throw ArgumentError("FaceId must not be zero");
+  }
+}
+
+StrategyChoiceSetCommand::StrategyChoiceSetCommand()
+  : ControlCommand("strategy-choice", "set")
+{
+  m_requestValidator
+    .required(CONTROL_PARAMETER_NAME)
+    .required(CONTROL_PARAMETER_STRATEGY);
+  m_responseValidator = m_requestValidator;
+}
+
+StrategyChoiceUnsetCommand::StrategyChoiceUnsetCommand()
+  : ControlCommand("strategy-choice", "unset")
+{
+  m_requestValidator
+    .required(CONTROL_PARAMETER_NAME);
+  m_responseValidator = m_requestValidator;
+}
+
+void
+StrategyChoiceUnsetCommand::validateRequest(const ControlParameters& parameters) const
+{
+  this->ControlCommand::validateRequest(parameters);
+
+  if (parameters.getName().size() == 0) {
+    throw ArgumentError("Name must not be ndn:/");
+  }
+}
+
+void
+StrategyChoiceUnsetCommand::validateResponse(const ControlParameters& parameters) const
+{
+  this->validateRequest(parameters);
+}
+
+RibRegisterCommand::RibRegisterCommand()
+  : ControlCommand("rib", "register")
+{
+  m_requestValidator
+    .required(CONTROL_PARAMETER_NAME)
+    .optional(CONTROL_PARAMETER_FACE_ID)
+    .optional(CONTROL_PARAMETER_ORIGIN)
+    .optional(CONTROL_PARAMETER_COST)
+    .optional(CONTROL_PARAMETER_FLAGS)
+    .optional(CONTROL_PARAMETER_EXPIRATION_PERIOD);
+  m_responseValidator
+    .required(CONTROL_PARAMETER_NAME)
+    .required(CONTROL_PARAMETER_FACE_ID)
+    .required(CONTROL_PARAMETER_ORIGIN)
+    .required(CONTROL_PARAMETER_COST)
+    .required(CONTROL_PARAMETER_FLAGS)
+    .optional(CONTROL_PARAMETER_EXPIRATION_PERIOD);
+}
+
+void
+RibRegisterCommand::applyDefaultsToRequest(ControlParameters& parameters) const
+{
+  if (!parameters.hasFaceId()) {
+    parameters.setFaceId(0);
+  }
+  if (!parameters.hasOrigin()) {
+    parameters.setOrigin(ROUTE_ORIGIN_APP);
+  }
+  if (!parameters.hasCost()) {
+    parameters.setCost(0);
+  }
+  if (!parameters.hasFlags()) {
+    parameters.setFlags(ROUTE_FLAG_CHILD_INHERIT);
+  }
+}
+
+void
+RibRegisterCommand::validateResponse(const ControlParameters& parameters) const
+{
+  this->ControlCommand::validateResponse(parameters);
+
+  if (parameters.getFaceId() == 0) {
+    throw ArgumentError("FaceId must not be zero");
+  }
+}
+
+RibUnregisterCommand::RibUnregisterCommand()
+  : ControlCommand("rib", "unregister")
+{
+  m_requestValidator
+    .required(CONTROL_PARAMETER_NAME)
+    .optional(CONTROL_PARAMETER_FACE_ID)
+    .optional(CONTROL_PARAMETER_ORIGIN);
+  m_responseValidator
+    .required(CONTROL_PARAMETER_NAME)
+    .required(CONTROL_PARAMETER_FACE_ID)
+    .required(CONTROL_PARAMETER_ORIGIN);
+}
+
+void
+RibUnregisterCommand::applyDefaultsToRequest(ControlParameters& parameters) const
+{
+  if (!parameters.hasFaceId()) {
+    parameters.setFaceId(0);
+  }
+  if (!parameters.hasOrigin()) {
+    parameters.setOrigin(ROUTE_ORIGIN_APP);
+  }
+}
+
+void
+RibUnregisterCommand::validateResponse(const ControlParameters& parameters) const
+{
+  this->ControlCommand::validateResponse(parameters);
+
+  if (parameters.getFaceId() == 0) {
+    throw ArgumentError("FaceId must not be zero");
+  }
+}
+
+} // namespace nfd
+} // namespace ndn
diff --git a/src/management/nfd-control-command.hpp b/src/management/nfd-control-command.hpp
index 3a4ad80..bc4ef53 100644
--- a/src/management/nfd-control-command.hpp
+++ b/src/management/nfd-control-command.hpp
@@ -36,10 +36,6 @@
 class ControlCommand : noncopyable
 {
 public:
-  /** \brief a callback on signing command interest
-   */
-  typedef function<void(Interest&)> Sign;
-
   /** \brief represents an error in ControlParameters
    */
   class ArgumentError : public std::invalid_argument
@@ -60,68 +56,52 @@
     return m_prefix;
   }
 
-  /** \brief make a Command Interest from parameters
-   */
-  Interest
-  makeCommandInterest(const ControlParameters& parameters,
-                      const Sign& sign) const
-  {
-    this->validateRequest(parameters);
-
-    Name name = m_prefix;
-    name.append(parameters.wireEncode());
-    Interest commandInterest(name);
-    sign(commandInterest);
-    return commandInterest;
-  }
-
   /** \brief validate request parameters
    *  \throw ArgumentError
    */
   virtual void
-  validateRequest(const ControlParameters& parameters) const
-  {
-    m_requestValidator.validate(parameters);
-  }
+  validateRequest(const ControlParameters& parameters) const;
 
   /** \brief apply default values to missing fields in request
    */
   virtual void
-  applyDefaultsToRequest(ControlParameters& parameters) const
-  {
-  }
+  applyDefaultsToRequest(ControlParameters& parameters) const;
 
   /** \brief validate response parameters
    *  \throw ArgumentError
    */
   virtual void
-  validateResponse(const ControlParameters& parameters) const
-  {
-    m_responseValidator.validate(parameters);
-  }
+  validateResponse(const ControlParameters& parameters) const;
 
   /** \brief apply default values to missing fields in response
    */
   virtual void
-  applyDefaultsToResponse(ControlParameters& parameters) const
-  {
-  }
+  applyDefaultsToResponse(ControlParameters& parameters) const;
+
+  /** \brief construct the Name for a request Interest
+   */
+  Name
+  getRequestName(const ControlParameters& parameters) const;
+
+public: // deprecated
+  /** \brief a callback on signing command interest
+   */
+  typedef function<void(Interest&)> Sign;
+
+  /** \brief make a Command Interest from parameters
+   *  \deprecated use .getCommandName and sign with KeyChain
+   */
+  Interest
+  makeCommandInterest(const ControlParameters& parameters,
+                      const Sign& sign) const;
 
 protected:
-  ControlCommand(const std::string& module, const std::string& verb)
-    : m_prefix("ndn:/localhost/nfd")
-  {
-    m_prefix.append(module).append(verb);
-  }
+  ControlCommand(const std::string& module, const std::string& verb);
 
   class FieldValidator
   {
   public:
-    FieldValidator()
-      : m_required(CONTROL_PARAMETER_UBOUND)
-      , m_optional(CONTROL_PARAMETER_UBOUND)
-    {
-    }
+    FieldValidator();
 
     /** \brief declare a required field
      */
@@ -146,22 +126,7 @@
      *  \throw ArgumentError
      */
     void
-    validate(const ControlParameters& parameters) const
-    {
-      const std::vector<bool>& presentFields = parameters.getPresentFields();
-
-      for (size_t i = 0; i < CONTROL_PARAMETER_UBOUND; ++i) {
-        bool isPresent = presentFields[i];
-        if (m_required[i]) {
-          if (!isPresent) {
-            throw ArgumentError(CONTROL_PARAMETER_FIELD[i] + " is required but missing");
-          }
-        }
-        else if (isPresent && !m_optional[i]) {
-          throw ArgumentError(CONTROL_PARAMETER_FIELD[i] + " is forbidden but present");
-        }
-      }
-    }
+    validate(const ControlParameters& parameters) const;
 
   private:
     std::vector<bool> m_required;
@@ -193,25 +158,10 @@
 class FaceCreateCommand : public ControlCommand
 {
 public:
-  FaceCreateCommand()
-    : ControlCommand("faces", "create")
-  {
-    m_requestValidator
-      .required(CONTROL_PARAMETER_URI);
-    m_responseValidator
-      .required(CONTROL_PARAMETER_URI)
-      .required(CONTROL_PARAMETER_FACE_ID);
-  }
+  FaceCreateCommand();
 
   virtual void
-  validateResponse(const ControlParameters& parameters) const
-  {
-    this->ControlCommand::validateResponse(parameters);
-
-    if (parameters.getFaceId() == 0) {
-      throw ArgumentError("FaceId must not be zero");
-    }
-  }
+  validateResponse(const ControlParameters& parameters) const;
 };
 
 
@@ -223,29 +173,13 @@
 class FaceDestroyCommand : public ControlCommand
 {
 public:
-  FaceDestroyCommand()
-    : ControlCommand("faces", "destroy")
-  {
-    m_requestValidator
-      .required(CONTROL_PARAMETER_FACE_ID);
-    m_responseValidator = m_requestValidator;
-  }
+  FaceDestroyCommand();
 
   virtual void
-  validateRequest(const ControlParameters& parameters) const
-  {
-    this->ControlCommand::validateRequest(parameters);
-
-    if (parameters.getFaceId() == 0) {
-      throw ArgumentError("FaceId must not be zero");
-    }
-  }
+  validateRequest(const ControlParameters& parameters) const;
 
   virtual void
-  validateResponse(const ControlParameters& parameters) const
-  {
-    this->validateRequest(parameters);
-  }
+  validateResponse(const ControlParameters& parameters) const;
 };
 
 /**
@@ -256,34 +190,14 @@
 {
 public:
   virtual void
-  validateRequest(const ControlParameters& parameters) const
-  {
-    this->ControlCommand::validateRequest(parameters);
-
-    switch (parameters.getLocalControlFeature()) {
-      case LOCAL_CONTROL_FEATURE_INCOMING_FACE_ID:
-      case LOCAL_CONTROL_FEATURE_NEXT_HOP_FACE_ID:
-        break;
-      default:
-        throw ArgumentError("LocalControlFeature is invalid");
-    }
-  }
+  validateRequest(const ControlParameters& parameters) const;
 
   virtual void
-  validateResponse(const ControlParameters& parameters) const
-  {
-    this->validateRequest(parameters);
-  }
+  validateResponse(const ControlParameters& parameters) const;
 
 protected:
   explicit
-  FaceLocalControlCommand(const std::string& verb)
-    : ControlCommand("faces", verb)
-  {
-    m_requestValidator
-      .required(CONTROL_PARAMETER_LOCAL_CONTROL_FEATURE);
-    m_responseValidator = m_requestValidator;
-  }
+  FaceLocalControlCommand(const std::string& verb);
 };
 
 
@@ -295,10 +209,7 @@
 class FaceEnableLocalControlCommand : public FaceLocalControlCommand
 {
 public:
-  FaceEnableLocalControlCommand()
-    : FaceLocalControlCommand("enable-local-control")
-  {
-  }
+  FaceEnableLocalControlCommand();
 };
 
 
@@ -310,10 +221,7 @@
 class FaceDisableLocalControlCommand : public FaceLocalControlCommand
 {
 public:
-  FaceDisableLocalControlCommand()
-    : FaceLocalControlCommand("disable-local-control")
-  {
-  }
+  FaceDisableLocalControlCommand();
 };
 
 
@@ -325,39 +233,13 @@
 class FibAddNextHopCommand : public ControlCommand
 {
 public:
-  FibAddNextHopCommand()
-    : ControlCommand("fib", "add-nexthop")
-  {
-    m_requestValidator
-      .required(CONTROL_PARAMETER_NAME)
-      .optional(CONTROL_PARAMETER_FACE_ID)
-      .optional(CONTROL_PARAMETER_COST);
-    m_responseValidator
-      .required(CONTROL_PARAMETER_NAME)
-      .required(CONTROL_PARAMETER_FACE_ID)
-      .required(CONTROL_PARAMETER_COST);
-  }
+  FibAddNextHopCommand();
 
   virtual void
-  applyDefaultsToRequest(ControlParameters& parameters) const
-  {
-    if (!parameters.hasFaceId()) {
-      parameters.setFaceId(0);
-    }
-    if (!parameters.hasCost()) {
-      parameters.setCost(0);
-    }
-  }
+  applyDefaultsToRequest(ControlParameters& parameters) const;
 
   virtual void
-  validateResponse(const ControlParameters& parameters) const
-  {
-    this->ControlCommand::validateResponse(parameters);
-
-    if (parameters.getFaceId() == 0) {
-      throw ArgumentError("FaceId must not be zero");
-    }
-  }
+  validateResponse(const ControlParameters& parameters) const;
 };
 
 
@@ -369,34 +251,13 @@
 class FibRemoveNextHopCommand : public ControlCommand
 {
 public:
-  FibRemoveNextHopCommand()
-    : ControlCommand("fib", "remove-nexthop")
-  {
-    m_requestValidator
-      .required(CONTROL_PARAMETER_NAME)
-      .optional(CONTROL_PARAMETER_FACE_ID);
-    m_responseValidator
-      .required(CONTROL_PARAMETER_NAME)
-      .required(CONTROL_PARAMETER_FACE_ID);
-  }
+  FibRemoveNextHopCommand();
 
   virtual void
-  applyDefaultsToRequest(ControlParameters& parameters) const
-  {
-    if (!parameters.hasFaceId()) {
-      parameters.setFaceId(0);
-    }
-  }
+  applyDefaultsToRequest(ControlParameters& parameters) const;
 
   virtual void
-  validateResponse(const ControlParameters& parameters) const
-  {
-    this->ControlCommand::validateResponse(parameters);
-
-    if (parameters.getFaceId() == 0) {
-      throw ArgumentError("FaceId must not be zero");
-    }
-  }
+  validateResponse(const ControlParameters& parameters) const;
 };
 
 
@@ -408,14 +269,7 @@
 class StrategyChoiceSetCommand : public ControlCommand
 {
 public:
-  StrategyChoiceSetCommand()
-    : ControlCommand("strategy-choice", "set")
-  {
-    m_requestValidator
-      .required(CONTROL_PARAMETER_NAME)
-      .required(CONTROL_PARAMETER_STRATEGY);
-    m_responseValidator = m_requestValidator;
-  }
+  StrategyChoiceSetCommand();
 };
 
 
@@ -427,29 +281,13 @@
 class StrategyChoiceUnsetCommand : public ControlCommand
 {
 public:
-  StrategyChoiceUnsetCommand()
-    : ControlCommand("strategy-choice", "unset")
-  {
-    m_requestValidator
-      .required(CONTROL_PARAMETER_NAME);
-    m_responseValidator = m_requestValidator;
-  }
+  StrategyChoiceUnsetCommand();
 
   virtual void
-  validateRequest(const ControlParameters& parameters) const
-  {
-    this->ControlCommand::validateRequest(parameters);
-
-    if (parameters.getName().size() == 0) {
-      throw ArgumentError("Name must not be ndn:/");
-    }
-  }
+  validateRequest(const ControlParameters& parameters) const;
 
   virtual void
-  validateResponse(const ControlParameters& parameters) const
-  {
-    this->validateRequest(parameters);
-  }
+  validateResponse(const ControlParameters& parameters) const;
 };
 
 
@@ -461,51 +299,13 @@
 class RibRegisterCommand : public ControlCommand
 {
 public:
-  RibRegisterCommand()
-    : ControlCommand("rib", "register")
-  {
-    m_requestValidator
-      .required(CONTROL_PARAMETER_NAME)
-      .optional(CONTROL_PARAMETER_FACE_ID)
-      .optional(CONTROL_PARAMETER_ORIGIN)
-      .optional(CONTROL_PARAMETER_COST)
-      .optional(CONTROL_PARAMETER_FLAGS)
-      .optional(CONTROL_PARAMETER_EXPIRATION_PERIOD);
-    m_responseValidator
-      .required(CONTROL_PARAMETER_NAME)
-      .required(CONTROL_PARAMETER_FACE_ID)
-      .required(CONTROL_PARAMETER_ORIGIN)
-      .required(CONTROL_PARAMETER_COST)
-      .required(CONTROL_PARAMETER_FLAGS)
-      .optional(CONTROL_PARAMETER_EXPIRATION_PERIOD);
-  }
+  RibRegisterCommand();
 
   virtual void
-  applyDefaultsToRequest(ControlParameters& parameters) const
-  {
-    if (!parameters.hasFaceId()) {
-      parameters.setFaceId(0);
-    }
-    if (!parameters.hasOrigin()) {
-      parameters.setOrigin(ROUTE_ORIGIN_APP);
-    }
-    if (!parameters.hasCost()) {
-      parameters.setCost(0);
-    }
-    if (!parameters.hasFlags()) {
-      parameters.setFlags(ROUTE_FLAG_CHILD_INHERIT);
-    }
-  }
+  applyDefaultsToRequest(ControlParameters& parameters) const;
 
   virtual void
-  validateResponse(const ControlParameters& parameters) const
-  {
-    this->ControlCommand::validateResponse(parameters);
-
-    if (parameters.getFaceId() == 0) {
-      throw ArgumentError("FaceId must not be zero");
-    }
-  }
+  validateResponse(const ControlParameters& parameters) const;
 };
 
 
@@ -517,39 +317,13 @@
 class RibUnregisterCommand : public ControlCommand
 {
 public:
-  RibUnregisterCommand()
-    : ControlCommand("rib", "unregister")
-  {
-    m_requestValidator
-      .required(CONTROL_PARAMETER_NAME)
-      .optional(CONTROL_PARAMETER_FACE_ID)
-      .optional(CONTROL_PARAMETER_ORIGIN);
-    m_responseValidator
-      .required(CONTROL_PARAMETER_NAME)
-      .required(CONTROL_PARAMETER_FACE_ID)
-      .required(CONTROL_PARAMETER_ORIGIN);
-  }
+  RibUnregisterCommand();
 
   virtual void
-  applyDefaultsToRequest(ControlParameters& parameters) const
-  {
-    if (!parameters.hasFaceId()) {
-      parameters.setFaceId(0);
-    }
-    if (!parameters.hasOrigin()) {
-      parameters.setOrigin(ROUTE_ORIGIN_APP);
-    }
-  }
+  applyDefaultsToRequest(ControlParameters& parameters) const;
 
   virtual void
-  validateResponse(const ControlParameters& parameters) const
-  {
-    this->ControlCommand::validateResponse(parameters);
-
-    if (parameters.getFaceId() == 0) {
-      throw ArgumentError("FaceId must not be zero");
-    }
-  }
+  validateResponse(const ControlParameters& parameters) const;
 };
 
 
diff --git a/src/management/nfd-control-parameters.cpp b/src/management/nfd-control-parameters.cpp
new file mode 100644
index 0000000..257dcb6
--- /dev/null
+++ b/src/management/nfd-control-parameters.cpp
@@ -0,0 +1,222 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "nfd-control-parameters.hpp"
+
+namespace ndn {
+namespace nfd {
+
+ControlParameters::ControlParameters()
+  : m_hasFields(CONTROL_PARAMETER_UBOUND)
+{
+}
+
+ControlParameters::ControlParameters(const Block& block)
+  : m_hasFields(CONTROL_PARAMETER_UBOUND)
+{
+  wireDecode(block);
+}
+
+template<bool T>
+size_t
+ControlParameters::wireEncode(EncodingImpl<T>& encoder) const
+{
+  size_t totalLength = 0;
+
+  if (this->hasExpirationPeriod()) {
+    totalLength += prependNonNegativeIntegerBlock(encoder,
+                   tlv::nfd::ExpirationPeriod, m_expirationPeriod.count());
+  }
+  if (this->hasStrategy()) {
+    totalLength += prependNestedBlock(encoder, tlv::nfd::Strategy, m_strategy);
+  }
+  if (this->hasFlags()) {
+    totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Flags, m_flags);
+  }
+  if (this->hasCost()) {
+    totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Cost, m_cost);
+  }
+  if (this->hasOrigin()) {
+    totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Origin, m_origin);
+  }
+  if (this->hasLocalControlFeature()) {
+    totalLength += prependNonNegativeIntegerBlock(encoder,
+                   tlv::nfd::LocalControlFeature, m_localControlFeature);
+  }
+  if (this->hasUri()) {
+    size_t valLength = encoder.prependByteArray(
+                       reinterpret_cast<const uint8_t*>(m_uri.c_str()), m_uri.size());
+    totalLength += valLength;
+    totalLength += encoder.prependVarNumber(valLength);
+    totalLength += encoder.prependVarNumber(tlv::nfd::Uri);
+  }
+  if (this->hasFaceId()) {
+    totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::FaceId, m_faceId);
+  }
+  if (this->hasName()) {
+    totalLength += m_name.wireEncode(encoder);
+  }
+
+  totalLength += encoder.prependVarNumber(totalLength);
+  totalLength += encoder.prependVarNumber(tlv::nfd::ControlParameters);
+  return totalLength;
+}
+
+template size_t
+ControlParameters::wireEncode<true>(EncodingImpl<true>& encoder) const;
+
+template size_t
+ControlParameters::wireEncode<false>(EncodingImpl<false>& estimator) const;
+
+const Block&
+ControlParameters::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
+ControlParameters::wireDecode(const Block& block)
+{
+  if (block.type() != tlv::nfd::ControlParameters) {
+    throw Error("expecting TLV-TYPE ControlParameters");
+  }
+  m_wire = block;
+  m_wire.parse();
+  Block::element_const_iterator val;
+
+  val = m_wire.find(tlv::Name);
+  m_hasFields[CONTROL_PARAMETER_NAME] = val != m_wire.elements_end();
+  if (this->hasName()) {
+    m_name.wireDecode(*val);
+  }
+
+  val = m_wire.find(tlv::nfd::FaceId);
+  m_hasFields[CONTROL_PARAMETER_FACE_ID] = val != m_wire.elements_end();
+  if (this->hasFaceId()) {
+    m_faceId = static_cast<uint64_t>(readNonNegativeInteger(*val));
+  }
+
+  val = m_wire.find(tlv::nfd::Uri);
+  m_hasFields[CONTROL_PARAMETER_URI] = val != m_wire.elements_end();
+  if (this->hasUri()) {
+    m_uri.assign(reinterpret_cast<const char*>(val->value()), val->value_size());
+  }
+
+  val = m_wire.find(tlv::nfd::LocalControlFeature);
+  m_hasFields[CONTROL_PARAMETER_LOCAL_CONTROL_FEATURE] = val != m_wire.elements_end();
+  if (this->hasLocalControlFeature()) {
+    m_localControlFeature = static_cast<LocalControlFeature>(readNonNegativeInteger(*val));
+  }
+
+  val = m_wire.find(tlv::nfd::Origin);
+  m_hasFields[CONTROL_PARAMETER_ORIGIN] = val != m_wire.elements_end();
+  if (this->hasOrigin()) {
+    m_origin = static_cast<uint64_t>(readNonNegativeInteger(*val));
+  }
+
+  val = m_wire.find(tlv::nfd::Cost);
+  m_hasFields[CONTROL_PARAMETER_COST] = val != m_wire.elements_end();
+  if (this->hasCost()) {
+    m_cost = static_cast<uint64_t>(readNonNegativeInteger(*val));
+  }
+
+  val = m_wire.find(tlv::nfd::Flags);
+  m_hasFields[CONTROL_PARAMETER_FLAGS] = val != m_wire.elements_end();
+  if (this->hasFlags()) {
+    m_flags = static_cast<uint64_t>(readNonNegativeInteger(*val));
+  }
+
+  val = m_wire.find(tlv::nfd::Strategy);
+  m_hasFields[CONTROL_PARAMETER_STRATEGY] = val != m_wire.elements_end();
+  if (this->hasStrategy()) {
+    val->parse();
+    if (val->elements().empty()) {
+      throw Error("expecting Strategy/Name");
+    }
+    else {
+      m_strategy.wireDecode(*val->elements_begin());
+    }
+  }
+
+  val = m_wire.find(tlv::nfd::ExpirationPeriod);
+  m_hasFields[CONTROL_PARAMETER_EXPIRATION_PERIOD] = val != m_wire.elements_end();
+  if (this->hasExpirationPeriod()) {
+    m_expirationPeriod = time::milliseconds(readNonNegativeInteger(*val));
+  }
+}
+
+std::ostream&
+operator<<(std::ostream& os, const ControlParameters& parameters)
+{
+  os << "ControlParameters(";
+
+  if (parameters.hasName()) {
+    os << "Name: " << parameters.getName() << ", ";
+  }
+
+  if (parameters.hasFaceId()) {
+    os << "FaceId: " << parameters.getFaceId() << ", ";
+  }
+
+  if (parameters.hasUri()) {
+    os << "Uri: " << parameters.getUri() << ", ";
+  }
+
+  if (parameters.hasLocalControlFeature()) {
+    os << "LocalControlFeature: " << parameters.getLocalControlFeature() << ", ";
+  }
+
+  if (parameters.hasOrigin()) {
+    os << "Origin: " << parameters.getOrigin() << ", ";
+  }
+
+  if (parameters.hasCost()) {
+    os << "Cost: " << parameters.getCost() << ", ";
+  }
+
+  if (parameters.hasFlags()) {
+    os << "Flags: " << parameters.getFlags() << ", ";
+  }
+
+  if (parameters.hasStrategy()) {
+    os << "Strategy: " << parameters.getStrategy() << ", ";
+  }
+
+  if (parameters.hasExpirationPeriod()) {
+    os << "ExpirationPeriod: " << parameters.getExpirationPeriod() << ", ";
+  }
+
+  os << ")";
+  return os;
+}
+
+} // namespace nfd
+} // namespace ndn
diff --git a/src/management/nfd-control-parameters.hpp b/src/management/nfd-control-parameters.hpp
index 0ab0f84..61381cb 100644
--- a/src/management/nfd-control-parameters.hpp
+++ b/src/management/nfd-control-parameters.hpp
@@ -67,9 +67,10 @@
 };
 
 /**
- * \ingroup management
- * \brief represents parameters in a ControlCommand request or response
- * \sa http://redmine.named-data.net/projects/nfd/wiki/ControlCommand
+ * @ingroup management
+ * @brief represents parameters in a ControlCommand request or response
+ * @sa http://redmine.named-data.net/projects/nfd/wiki/ControlCommand#ControlParameters
+ * @detail This type is copyable because it's an abstraction of a TLV type.
  */
 class ControlParameters
 {
@@ -84,17 +85,10 @@
     }
   };
 
-  ControlParameters()
-    : m_hasFields(CONTROL_PARAMETER_UBOUND)
-  {
-  }
+  ControlParameters();
 
   explicit
-  ControlParameters(const Block& block)
-    : m_hasFields(CONTROL_PARAMETER_UBOUND)
-  {
-    wireDecode(block);
-  }
+  ControlParameters(const Block& block);
 
   template<bool T>
   size_t
@@ -401,184 +395,8 @@
   mutable Block m_wire;
 };
 
-
-template<bool T>
-inline size_t
-ControlParameters::wireEncode(EncodingImpl<T>& encoder) const
-{
-  size_t totalLength = 0;
-
-  if (this->hasExpirationPeriod()) {
-    totalLength += prependNonNegativeIntegerBlock(encoder,
-                   tlv::nfd::ExpirationPeriod, m_expirationPeriod.count());
-  }
-  if (this->hasStrategy()) {
-    totalLength += prependNestedBlock(encoder, tlv::nfd::Strategy, m_strategy);
-  }
-  if (this->hasFlags()) {
-    totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Flags, m_flags);
-  }
-  if (this->hasCost()) {
-    totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Cost, m_cost);
-  }
-  if (this->hasOrigin()) {
-    totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::Origin, m_origin);
-  }
-  if (this->hasLocalControlFeature()) {
-    totalLength += prependNonNegativeIntegerBlock(encoder,
-                   tlv::nfd::LocalControlFeature, m_localControlFeature);
-  }
-  if (this->hasUri()) {
-    size_t valLength = encoder.prependByteArray(
-                       reinterpret_cast<const uint8_t*>(m_uri.c_str()), m_uri.size());
-    totalLength += valLength;
-    totalLength += encoder.prependVarNumber(valLength);
-    totalLength += encoder.prependVarNumber(tlv::nfd::Uri);
-  }
-  if (this->hasFaceId()) {
-    totalLength += prependNonNegativeIntegerBlock(encoder, tlv::nfd::FaceId, m_faceId);
-  }
-  if (this->hasName()) {
-    totalLength += m_name.wireEncode(encoder);
-  }
-
-  totalLength += encoder.prependVarNumber(totalLength);
-  totalLength += encoder.prependVarNumber(tlv::nfd::ControlParameters);
-  return totalLength;
-}
-
-inline const Block&
-ControlParameters::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
-ControlParameters::wireDecode(const Block& block)
-{
-  if (block.type() != tlv::nfd::ControlParameters) {
-    throw Error("expecting TLV-TYPE ControlParameters");
-  }
-  m_wire = block;
-  m_wire.parse();
-  Block::element_const_iterator val;
-
-  val = m_wire.find(tlv::Name);
-  m_hasFields[CONTROL_PARAMETER_NAME] = val != m_wire.elements_end();
-  if (this->hasName()) {
-    m_name.wireDecode(*val);
-  }
-
-  val = m_wire.find(tlv::nfd::FaceId);
-  m_hasFields[CONTROL_PARAMETER_FACE_ID] = val != m_wire.elements_end();
-  if (this->hasFaceId()) {
-    m_faceId = static_cast<uint64_t>(readNonNegativeInteger(*val));
-  }
-
-  val = m_wire.find(tlv::nfd::Uri);
-  m_hasFields[CONTROL_PARAMETER_URI] = val != m_wire.elements_end();
-  if (this->hasUri()) {
-    m_uri.assign(reinterpret_cast<const char*>(val->value()), val->value_size());
-  }
-
-  val = m_wire.find(tlv::nfd::LocalControlFeature);
-  m_hasFields[CONTROL_PARAMETER_LOCAL_CONTROL_FEATURE] = val != m_wire.elements_end();
-  if (this->hasLocalControlFeature()) {
-    m_localControlFeature = static_cast<LocalControlFeature>(readNonNegativeInteger(*val));
-  }
-
-  val = m_wire.find(tlv::nfd::Origin);
-  m_hasFields[CONTROL_PARAMETER_ORIGIN] = val != m_wire.elements_end();
-  if (this->hasOrigin()) {
-    m_origin = static_cast<uint64_t>(readNonNegativeInteger(*val));
-  }
-
-  val = m_wire.find(tlv::nfd::Cost);
-  m_hasFields[CONTROL_PARAMETER_COST] = val != m_wire.elements_end();
-  if (this->hasCost()) {
-    m_cost = static_cast<uint64_t>(readNonNegativeInteger(*val));
-  }
-
-  val = m_wire.find(tlv::nfd::Flags);
-  m_hasFields[CONTROL_PARAMETER_FLAGS] = val != m_wire.elements_end();
-  if (this->hasFlags()) {
-    m_flags = static_cast<uint64_t>(readNonNegativeInteger(*val));
-  }
-
-  val = m_wire.find(tlv::nfd::Strategy);
-  m_hasFields[CONTROL_PARAMETER_STRATEGY] = val != m_wire.elements_end();
-  if (this->hasStrategy()) {
-    val->parse();
-    if (val->elements().empty()) {
-      throw Error("expecting Strategy/Name");
-    }
-    else {
-      m_strategy.wireDecode(*val->elements_begin());
-    }
-  }
-
-  val = m_wire.find(tlv::nfd::ExpirationPeriod);
-  m_hasFields[CONTROL_PARAMETER_EXPIRATION_PERIOD] = val != m_wire.elements_end();
-  if (this->hasExpirationPeriod()) {
-    m_expirationPeriod = time::milliseconds(readNonNegativeInteger(*val));
-  }
-}
-
-inline std::ostream&
-operator<<(std::ostream& os, const ControlParameters& parameters)
-{
-  os << "ControlParameters(";
-
-  if (parameters.hasName()) {
-    os << "Name: " << parameters.getName() << ", ";
-  }
-
-  if (parameters.hasFaceId()) {
-    os << "FaceId: " << parameters.getFaceId() << ", ";
-  }
-
-  if (parameters.hasUri()) {
-    os << "Uri: " << parameters.getUri() << ", ";
-  }
-
-  if (parameters.hasLocalControlFeature()) {
-    os << "LocalControlFeature: " << parameters.getLocalControlFeature() << ", ";
-  }
-
-  if (parameters.hasOrigin()) {
-    os << "Origin: " << parameters.getOrigin() << ", ";
-  }
-
-  if (parameters.hasCost()) {
-    os << "Cost: " << parameters.getCost() << ", ";
-  }
-
-  if (parameters.hasFlags()) {
-    os << "Flags: " << parameters.getFlags() << ", ";
-  }
-
-  if (parameters.hasStrategy()) {
-    os << "Strategy: " << parameters.getStrategy() << ", ";
-  }
-
-  if (parameters.hasExpirationPeriod()) {
-    os << "ExpirationPeriod: " << parameters.getExpirationPeriod() << ", ";
-  }
-
-  os << ")";
-  return os;
-}
-
+std::ostream&
+operator<<(std::ostream& os, const ControlParameters& parameters);
 
 } // namespace nfd
 } // namespace ndn
diff --git a/src/management/nfd-control-response.cpp b/src/management/nfd-control-response.cpp
new file mode 100644
index 0000000..568dace
--- /dev/null
+++ b/src/management/nfd-control-response.cpp
@@ -0,0 +1,106 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "nfd-control-response.hpp"
+
+namespace ndn {
+namespace nfd {
+
+ControlResponse::ControlResponse()
+  : m_code(200)
+{
+}
+
+ControlResponse::ControlResponse(uint32_t code, const std::string& text)
+  : m_code(code)
+  , m_text(text)
+{
+}
+
+ControlResponse::ControlResponse(const Block& block)
+{
+  wireDecode(block);
+}
+
+const Block&
+ControlResponse::wireEncode() const
+{
+  if (m_wire.hasWire())
+    return m_wire;
+
+  m_wire = Block(tlv::nfd::ControlResponse);
+  m_wire.push_back
+    (nonNegativeIntegerBlock(tlv::nfd::StatusCode, m_code));
+
+  m_wire.push_back
+    (dataBlock(tlv::nfd::StatusText, m_text.c_str(), m_text.size()));
+
+  if (m_body.hasWire())
+    {
+      m_wire.push_back(m_body);
+    }
+
+  m_wire.encode();
+  return m_wire;
+}
+
+void
+ControlResponse::wireDecode(const Block& wire)
+{
+  m_wire = wire;
+  m_wire.parse();
+
+  if (m_wire.type() != tlv::nfd::ControlResponse)
+    throw Error("Requested decoding of ControlResponse, but Block is of different type");
+
+  Block::element_const_iterator val = m_wire.elements_begin();
+  if (val == m_wire.elements_end() ||
+      val->type() != tlv::nfd::StatusCode)
+    {
+      throw Error("Incorrect ControlResponse format (StatusCode missing or not the first item)");
+    }
+
+  m_code = readNonNegativeInteger(*val);
+  ++val;
+
+  if (val == m_wire.elements_end() ||
+      val->type() != tlv::nfd::StatusText)
+    {
+      throw Error("Incorrect ControlResponse format (StatusText missing or not the second item)");
+    }
+  m_text.assign(reinterpret_cast<const char*>(val->value()), val->value_size());
+  ++val;
+
+  if (val != m_wire.elements_end())
+    m_body = *val;
+  else
+    m_body = Block();
+}
+
+std::ostream&
+operator<<(std::ostream& os, const ControlResponse& response)
+{
+  os << response.getCode() << " " << response.getText();
+  return os;
+}
+
+} // namespace nfd
+} // namespace ndn
diff --git a/src/management/nfd-control-response.hpp b/src/management/nfd-control-response.hpp
index 29aa832..2ad94e5 100644
--- a/src/management/nfd-control-response.hpp
+++ b/src/management/nfd-control-response.hpp
@@ -33,7 +33,8 @@
  * @ingroup management
  * @brief Class defining abstraction of ControlResponse for NFD Control Protocol
  *
- * @see http://redmine.named-data.net/projects/nfd/wiki/ControlCommand
+ * @see http://redmine.named-data.net/projects/nfd/wiki/ControlCommand#Response-format
+ * @detail This type is copyable because it's an abstraction of a TLV type.
  */
 class ControlResponse
 {
@@ -48,44 +49,35 @@
     }
   };
 
-  ControlResponse()
-    : m_code(200)
-  {
-  }
+  ControlResponse();
 
-  ControlResponse(uint32_t code, const std::string& text)
-    : m_code(code)
-    , m_text(text)
-  {
-  }
+  ControlResponse(uint32_t code, const std::string& text);
 
-  ControlResponse(const Block& block)
-  {
-    wireDecode(block);
-  }
+  explicit
+  ControlResponse(const Block& block);
 
-  inline uint32_t
+  uint32_t
   getCode() const;
 
-  inline void
+  void
   setCode(uint32_t code);
 
-  inline const std::string&
+  const std::string&
   getText() const;
 
-  inline void
+  void
   setText(const std::string& text);
 
-  inline const Block&
+  const Block&
   getBody() const;
 
-  inline void
+  void
   setBody(const Block& body);
 
-  inline const Block&
+  const Block&
   wireEncode() const;
 
-  inline void
+  void
   wireDecode(const Block& block);
 
 protected:
@@ -136,68 +128,8 @@
   m_wire.reset();
 }
 
-
-inline const Block&
-ControlResponse::wireEncode() const
-{
-  if (m_wire.hasWire())
-    return m_wire;
-
-  m_wire = Block(tlv::nfd::ControlResponse);
-  m_wire.push_back
-    (nonNegativeIntegerBlock(tlv::nfd::StatusCode, m_code));
-
-  m_wire.push_back
-    (dataBlock(tlv::nfd::StatusText, m_text.c_str(), m_text.size()));
-
-  if (m_body.hasWire())
-    {
-      m_wire.push_back(m_body);
-    }
-
-  m_wire.encode();
-  return m_wire;
-}
-
-inline void
-ControlResponse::wireDecode(const Block& wire)
-{
-  m_wire = wire;
-  m_wire.parse();
-
-  if (m_wire.type() != tlv::nfd::ControlResponse)
-    throw Error("Requested decoding of ControlResponse, but Block is of different type");
-
-  Block::element_const_iterator val = m_wire.elements_begin();
-  if (val == m_wire.elements_end() ||
-      val->type() != tlv::nfd::StatusCode)
-    {
-      throw Error("Incorrect ControlResponse format (StatusCode missing or not the first item)");
-    }
-
-  m_code = readNonNegativeInteger(*val);
-  ++val;
-
-  if (val == m_wire.elements_end() ||
-      val->type() != tlv::nfd::StatusText)
-    {
-      throw Error("Incorrect ControlResponse format (StatusText missing or not the second item)");
-    }
-  m_text.assign(reinterpret_cast<const char*>(val->value()), val->value_size());
-  ++val;
-
-  if (val != m_wire.elements_end())
-    m_body = *val;
-  else
-    m_body = Block();
-}
-
-inline std::ostream&
-operator << (std::ostream& os, const ControlResponse& status)
-{
-  os << status.getCode() << " " << status.getText();
-  return os;
-}
+std::ostream&
+operator<<(std::ostream& os, const ControlResponse& response);
 
 } // namespace nfd
 } // namespace ndn
diff --git a/src/management/nfd-controller.cpp b/src/management/nfd-controller.cpp
index 3b7056e..2d5b348 100644
--- a/src/management/nfd-controller.cpp
+++ b/src/management/nfd-controller.cpp
@@ -21,16 +21,46 @@
 
 #include "nfd-controller.hpp"
 #include "nfd-control-response.hpp"
-#include "../security/identity-certificate.hpp"
 
 namespace ndn {
 namespace nfd {
 
 Controller::Controller(Face& face)
   : m_face(face)
+  , m_internalKeyChain(make_shared<KeyChain>())
+  , m_keyChain(*m_internalKeyChain)
 {
 }
 
+Controller::Controller(Face& face, KeyChain& keyChain)
+  : m_face(face)
+  , m_keyChain(keyChain)
+{
+}
+
+void
+Controller::startCommand(const shared_ptr<ControlCommand>& command,
+                         const ControlParameters& parameters,
+                         const CommandSucceedCallback& onSuccess,
+                         const CommandFailCallback& onFailure,
+                         const Sign& sign,
+                         const time::milliseconds& timeout)
+{
+  BOOST_ASSERT(timeout > time::milliseconds::zero());
+
+  Name requestName = command->getRequestName(parameters);
+  Interest interest(requestName);
+  interest.setInterestLifetime(timeout);
+  sign(interest);
+
+  // http://msdn.microsoft.com/en-us/library/windows/desktop/ms740668.aspx
+  const uint32_t timeoutCode = 10060;
+  m_face.expressInterest(interest,
+                         bind(&Controller::processCommandResponse, this, _2,
+                              command, onSuccess, onFailure),
+                         bind(onFailure, timeoutCode, "Command Interest timed out"));
+}
+
 void
 Controller::processCommandResponse(const Data& data,
                                    const shared_ptr<ControlCommand>& command,
diff --git a/src/management/nfd-controller.hpp b/src/management/nfd-controller.hpp
index 8485693..4571336 100644
--- a/src/management/nfd-controller.hpp
+++ b/src/management/nfd-controller.hpp
@@ -24,6 +24,7 @@
 
 #include "nfd-control-command.hpp"
 #include "../face.hpp"
+#include "../security/key-chain.hpp"
 
 namespace ndn {
 namespace nfd {
@@ -47,13 +48,21 @@
    */
   typedef function<void(uint32_t/*code*/,const std::string&/*reason*/)> CommandFailCallback;
 
-  /** \brief a callback on signing command interest
+  /** \brief a function to sign the request Interest
    */
   typedef function<void(Interest&)> Sign;
 
+  /** \brief construct a Controller that uses face for transport,
+   *         and has an internal default KeyChain to sign commands
+   */
   explicit
   Controller(Face& face);
 
+  /** \brief construct a Controller that uses face for transport,
+   *         and uses the passed KeyChain to sign commands
+   */
+  Controller(Face& face, KeyChain& keyChain);
+
   /** \brief start command execution
    */
   template<typename Command>
@@ -61,15 +70,38 @@
   start(const ControlParameters& parameters,
         const CommandSucceedCallback& onSuccess,
         const CommandFailCallback& onFailure,
-        const IdentityCertificate& certificate = IdentityCertificate(),
         const time::milliseconds& timeout = getDefaultCommandTimeout())
   {
     start<Command>(parameters, onSuccess, onFailure,
-                   bind(&CommandInterestGenerator::generate,
-                        &m_commandInterestGenerator, _1, cref(certificate.getName())),
+                   bind(&KeyChain::sign<Interest>, &m_keyChain, _1),
                    timeout);
   }
 
+  /** \brief start command execution
+   *  \param certificate the certificate used to sign request Interests
+   *  \deprecated passing IdentityCertificate() empty certificate as fourth argument
+   *              is deprecated, use four-parameter overload instead
+   */
+  template<typename Command>
+  void
+  start(const ControlParameters& parameters,
+        const CommandSucceedCallback& onSuccess,
+        const CommandFailCallback& onFailure,
+        const IdentityCertificate& certificate,
+        const time::milliseconds& timeout = getDefaultCommandTimeout())
+  {
+    if (certificate.getName().empty()) { // deprecated usage
+      start<Command>(parameters, onSuccess, onFailure, timeout);
+    }
+    start<Command>(parameters, onSuccess, onFailure,
+      bind(static_cast<void(KeyChain::*)(Interest&,const Name&)>(&KeyChain::sign<Interest>),
+           &m_keyChain, _1, cref(certificate.getName())),
+      timeout);
+  }
+
+  /** \brief start command execution
+   *  \param identity the identity used to sign request Interests
+   */
   template<typename Command>
   void
   start(const ControlParameters& parameters,
@@ -79,21 +111,35 @@
         const time::milliseconds& timeout = getDefaultCommandTimeout())
   {
     start<Command>(parameters, onSuccess, onFailure,
-                   bind(&CommandInterestGenerator::generateWithIdentity,
-                        &m_commandInterestGenerator, _1, cref(identity)),
+                   bind(&KeyChain::signByIdentity<Interest>, &m_keyChain, _1, cref(identity)),
                    timeout);
   }
 
+  /** \brief start command execution
+   *  \param sign a function to sign request Interests
+   */
   template<typename Command>
   void
   start(const ControlParameters& parameters,
         const CommandSucceedCallback& onSuccess,
         const CommandFailCallback& onFailure,
         const Sign& sign,
-        const time::milliseconds& timeout = getDefaultCommandTimeout());
+        const time::milliseconds& timeout = getDefaultCommandTimeout())
+  {
+    shared_ptr<ControlCommand> command = make_shared<Command>();
+    this->startCommand(command, parameters, onSuccess, onFailure, sign, timeout);
+  }
 
 private:
   void
+  startCommand(const shared_ptr<ControlCommand>& command,
+               const ControlParameters& parameters,
+               const CommandSucceedCallback& onSuccess,
+               const CommandFailCallback& onFailure,
+               const Sign& sign,
+               const time::milliseconds& timeout);
+
+  void
   processCommandResponse(const Data& data,
                          const shared_ptr<ControlCommand>& command,
                          const CommandSucceedCallback& onSuccess,
@@ -108,33 +154,10 @@
 
 protected:
   Face& m_face;
-  CommandInterestGenerator m_commandInterestGenerator;
+  shared_ptr<KeyChain> m_internalKeyChain;
+  KeyChain& m_keyChain;
 };
 
-template<typename Command>
-inline void
-Controller::start(const ControlParameters& parameters,
-                  const CommandSucceedCallback& onSuccess,
-                  const CommandFailCallback&    onFailure,
-                  const Sign& sign,
-                  const time::milliseconds& timeout)
-{
-  BOOST_ASSERT(timeout > time::milliseconds::zero());
-
-  shared_ptr<ControlCommand> command = make_shared<Command>();
-
-  Interest commandInterest = command->makeCommandInterest(parameters, sign);
-
-  commandInterest.setInterestLifetime(timeout);
-
-  // http://msdn.microsoft.com/en-us/library/windows/desktop/ms740668.aspx
-  const uint32_t timeoutCode = 10060;
-  m_face.expressInterest(commandInterest,
-                         bind(&Controller::processCommandResponse, this, _2,
-                              command, onSuccess, onFailure),
-                         bind(onFailure, timeoutCode, "Command Interest timed out"));
-}
-
 } // namespace nfd
 } // namespace ndn
 
diff --git a/tests/unit-tests/management/test-nfd-controller.cpp b/tests/unit-tests/management/test-nfd-controller.cpp
index 7132c69..3792f2c 100644
--- a/tests/unit-tests/management/test-nfd-controller.cpp
+++ b/tests/unit-tests/management/test-nfd-controller.cpp
@@ -80,9 +80,9 @@
   parameters.setUri("tcp://example.com");
 
   BOOST_CHECK_NO_THROW(controller.start<FaceCreateCommand>(
-                         parameters,
-                         commandSucceedCallback,
-                         commandFailCallback));
+                       parameters,
+                       commandSucceedCallback,
+                       commandFailCallback));
   face->processEvents(time::milliseconds(1));
 
   BOOST_REQUIRE_EQUAL(face->m_sentInterests.size(), 1);