tools: nfdc creates Face and KeyChain in main function

refs #3749

Change-Id: I169ad766634371b0192ebae640355298b78aaaa4
diff --git a/tests/tools/nfdc/command-parser.t.cpp b/tests/tools/nfdc/command-parser.t.cpp
index 435392d..73ad3cc 100644
--- a/tests/tools/nfdc/command-parser.t.cpp
+++ b/tests/tools/nfdc/command-parser.t.cpp
@@ -40,72 +40,62 @@
 BOOST_AUTO_TEST_CASE(Basic)
 {
   CommandParser parser;
-
-  std::string lastName;
-  auto makeExecute = [&] (const std::string& name) {
-    return [&, name] (const CommandArguments& args) {
-      lastName = name;
-    };
-  };
+  ExecuteCommand dummyExecute = [] (ExecuteContext&) { return 0; };
 
   CommandDefinition defHelp("help", "");
   defHelp
     .addArg("noun", ArgValueType::STRING, Required::NO, Positional::YES)
     .addArg("verb", ArgValueType::STRING, Required::NO, Positional::YES);
-  parser.addCommand(defHelp, makeExecute("help"), AVAILABLE_IN_ONE_SHOT);
+  parser.addCommand(defHelp, dummyExecute, AVAILABLE_IN_ONE_SHOT);
 
   CommandDefinition defStatusShow("status", "show");
-  parser.addCommand(defStatusShow, makeExecute("status show"));
+  parser.addCommand(defStatusShow, dummyExecute);
   parser.addAlias("status", "show", "list");
   BOOST_CHECK_THROW(parser.addAlias("status", "show2", "list"), std::out_of_range);
 
   CommandDefinition defRouteList("route", "list");
   defRouteList
     .addArg("nexthop", ArgValueType::FACE_ID_OR_URI, Required::NO, Positional::YES);
-  parser.addCommand(defRouteList, makeExecute("route list"));
+  parser.addCommand(defRouteList, dummyExecute);
 
   CommandDefinition defRouteAdd("route", "add");
   defRouteAdd
     .addArg("prefix", ArgValueType::NAME, Required::YES, Positional::YES)
     .addArg("nexthop", ArgValueType::FACE_ID_OR_URI, Required::YES, Positional::YES);
-  parser.addCommand(defRouteAdd, makeExecute("route add"));
+  parser.addCommand(defRouteAdd, dummyExecute);
   parser.addAlias("route", "add", "add2");
 
 
-  CommandParser::Execute* execute = nullptr;
+  std::string noun, verb;
   CommandArguments ca;
+  ExecuteCommand execute;
 
-  std::tie(execute, ca) = parser.parse(std::vector<std::string>{"help"},
-                                       ParseMode::ONE_SHOT);
-  BOOST_REQUIRE(execute != nullptr);
-  (*execute)(ca);
-  BOOST_CHECK_EQUAL(lastName, "help");
+  std::tie(noun, verb, ca, execute) = parser.parse(
+    std::vector<std::string>{"help"}, ParseMode::ONE_SHOT);
+  BOOST_CHECK_EQUAL(noun, "help");
+  BOOST_CHECK_EQUAL(verb, "");
 
-  std::tie(execute, ca) = parser.parse(std::vector<std::string>{"status"},
-                                       ParseMode::ONE_SHOT);
-  BOOST_REQUIRE(execute != nullptr);
-  (*execute)(ca);
-  BOOST_CHECK_EQUAL(lastName, "status show");
+  std::tie(noun, verb, ca, execute) = parser.parse(
+    std::vector<std::string>{"status"}, ParseMode::ONE_SHOT);
+  BOOST_CHECK_EQUAL(noun, "status");
+  BOOST_CHECK_EQUAL(verb, "show");
 
-  std::tie(execute, ca) = parser.parse(std::vector<std::string>{"route", "add", "/n", "300"},
-                                       ParseMode::ONE_SHOT);
-  BOOST_REQUIRE(execute != nullptr);
-  (*execute)(ca);
-  BOOST_CHECK_EQUAL(lastName, "route add");
+  std::tie(noun, verb, ca, execute) = parser.parse(
+    std::vector<std::string>{"route", "add", "/n", "300"}, ParseMode::ONE_SHOT);
+  BOOST_CHECK_EQUAL(noun, "route");
+  BOOST_CHECK_EQUAL(verb, "add");
   BOOST_CHECK_EQUAL(boost::any_cast<Name>(ca.at("prefix")), "/n");
   BOOST_CHECK_EQUAL(boost::any_cast<uint64_t>(ca.at("nexthop")), 300);
 
-  std::tie(execute, ca) = parser.parse(std::vector<std::string>{"route", "add2", "/n", "300"},
-                                       ParseMode::ONE_SHOT);
-  BOOST_REQUIRE(execute != nullptr);
-  (*execute)(ca);
-  BOOST_CHECK_EQUAL(lastName, "route add");
+  std::tie(noun, verb, ca, execute) = parser.parse(
+    std::vector<std::string>{"route", "add2", "/n", "300"}, ParseMode::ONE_SHOT);
+  BOOST_CHECK_EQUAL(noun, "route");
+  BOOST_CHECK_EQUAL(verb, "add");
 
-  std::tie(execute, ca) = parser.parse(std::vector<std::string>{"route", "list", "400"},
-                                       ParseMode::ONE_SHOT);
-  BOOST_REQUIRE(execute != nullptr);
-  (*execute)(ca);
-  BOOST_CHECK_EQUAL(lastName, "route list");
+  std::tie(noun, verb, ca, execute) = parser.parse(
+    std::vector<std::string>{"route", "list", "400"}, ParseMode::ONE_SHOT);
+  BOOST_CHECK_EQUAL(noun, "route");
+  BOOST_CHECK_EQUAL(verb, "list");
   BOOST_CHECK_EQUAL(boost::any_cast<uint64_t>(ca.at("nexthop")), 400);
 
   BOOST_CHECK_THROW(parser.parse(std::vector<std::string>{}, ParseMode::ONE_SHOT),
@@ -120,7 +110,7 @@
                     CommandDefinition::Error);
 }
 
-BOOST_AUTO_TEST_SUITE_END() // TestCommandDefinition
+BOOST_AUTO_TEST_SUITE_END() // TestCommandParser
 BOOST_AUTO_TEST_SUITE_END() // Nfdc
 
 } // namespace tests
diff --git a/tools/nfdc/available-commands.cpp b/tools/nfdc/available-commands.cpp
index 3b6a393..99a53e0 100644
--- a/tools/nfdc/available-commands.cpp
+++ b/tools/nfdc/available-commands.cpp
@@ -32,36 +32,25 @@
 namespace tools {
 namespace nfdc {
 
-static void
-statusReport(const CommandArguments& ca)
+static int
+statusReport(ExecuteContext& ctx)
 {
-  int res = 1;
-  ReportFormat fmt = ca.get<ReportFormat>("format", ReportFormat::TEXT);
+  ReportFormat fmt = ctx.args.get<ReportFormat>("format", ReportFormat::TEXT);
   switch (fmt) {
     case ReportFormat::XML:
-      res = statusMain(std::vector<std::string>{"-x"});
-      break;
+      return statusMain(std::vector<std::string>{"-x"}, ctx.face, ctx.keyChain);
     case ReportFormat::TEXT:
-      res = statusMain(std::vector<std::string>{});
-      break;
+      return statusMain(std::vector<std::string>{}, ctx.face, ctx.keyChain);
   }
-  exit(res);
+  BOOST_ASSERT(false);
+  return 1;
 }
 
-static void
-legacyNfdStatus(const CommandArguments& ca)
+static int
+legacyNfdStatus(ExecuteContext& ctx)
 {
-  std::vector<std::string> args = ca.get<std::vector<std::string>>("args");
-  int res = statusMain(args);
-  exit(res);
-}
-
-static void
-legacyNfdc(const std::string& subcommand, const CommandArguments& ca)
-{
-  std::vector<std::string> args = ca.get<std::vector<std::string>>("args");
-  int res = legacyNfdcMain(subcommand, args);
-  exit(res);
+  auto args = ctx.args.get<std::vector<std::string>>("args");
+  return statusMain(args, ctx.face, ctx.keyChain);
 }
 
 void
@@ -90,7 +79,7 @@
   for (const std::string& subcommand : legacyNfdcSubcommands) {
     CommandDefinition def(subcommand, "");
     def.addArg("args", ArgValueType::ANY, Required::NO, Positional::YES);
-    parser.addCommand(def, bind(&legacyNfdc, subcommand, _1));
+    parser.addCommand(def, &legacyNfdcMain);
   }
 }
 
diff --git a/tools/nfdc/command-definition.cpp b/tools/nfdc/command-definition.cpp
index cf11928..cb25c7c 100644
--- a/tools/nfdc/command-definition.cpp
+++ b/tools/nfdc/command-definition.cpp
@@ -104,7 +104,7 @@
   bool isNew = m_args.emplace(name,
     Arg{name, valueType, static_cast<bool>(isRequired),
         metavar.empty() ? getMetavarFromType(valueType) : metavar}).second;
-  BOOST_ASSERT(isNew);
+  BOOST_VERIFY(isNew);
 
   if (static_cast<bool>(isRequired)) {
     m_requiredArgs.insert(name);
diff --git a/tools/nfdc/command-parser.cpp b/tools/nfdc/command-parser.cpp
index d91cbc3..974c931 100644
--- a/tools/nfdc/command-parser.cpp
+++ b/tools/nfdc/command-parser.cpp
@@ -69,7 +69,7 @@
 }
 
 CommandParser&
-CommandParser::addCommand(const CommandDefinition& def, const Execute& execute, AvailableIn modes)
+CommandParser::addCommand(const CommandDefinition& def, const ExecuteCommand& execute, AvailableIn modes)
 {
   BOOST_ASSERT(modes != AVAILABLE_IN_NONE);
   m_commands[{def.getNoun(), def.getVerb()}].reset(new Command{def, execute, modes});
@@ -83,7 +83,7 @@
   return *this;
 }
 
-std::tuple<CommandParser::Execute*, CommandArguments>
+std::tuple<std::string, std::string, CommandArguments, ExecuteCommand>
 CommandParser::parse(const std::vector<std::string>& tokens, ParseMode mode) const
 {
   BOOST_ASSERT(mode == ParseMode::ONE_SHOT);
@@ -110,7 +110,7 @@
   const CommandDefinition& def = i->second->def;
   NDN_LOG_TRACE("found command " << def.getNoun() << " " << def.getVerb());
 
-  return std::make_tuple(&i->second->execute, def.parse(tokens, nameLen));
+  return std::make_tuple(def.getNoun(), def.getVerb(), def.parse(tokens, nameLen), i->second->execute);
 }
 
 } // namespace nfdc
diff --git a/tools/nfdc/command-parser.hpp b/tools/nfdc/command-parser.hpp
index 7a1dbda..3a853c5 100644
--- a/tools/nfdc/command-parser.hpp
+++ b/tools/nfdc/command-parser.hpp
@@ -27,6 +27,7 @@
 #define NFD_TOOLS_NFDC_COMMAND_PARSER_HPP
 
 #include "command-definition.hpp"
+#include "execute-command.hpp"
 
 namespace nfd {
 namespace tools {
@@ -69,15 +70,13 @@
     }
   };
 
-  typedef std::function<void(const CommandArguments&)> Execute;
-
   /** \brief add an available command
    *  \param def command semantics definition
    *  \param execute a function to execute the command
    *  \param modes parse modes this command should be available in, must not be AVAILABLE_IN_NONE
    */
   CommandParser&
-  addCommand(const CommandDefinition& def, const Execute& execute, AvailableIn modes = AVAILABLE_IN_ALL);
+  addCommand(const CommandDefinition& def, const ExecuteCommand& execute, AvailableIn modes = AVAILABLE_IN_ALL);
 
   /** \brief add an alias "noun verb2" to existing command "noun verb"
    *  \throw std::out_of_range "noun verb" does not exist
@@ -90,8 +89,9 @@
    *  \param mode parser mode, must be ParseMode::ONE_SHOT, other modes are not implemented
    *  \throw Error command is not found
    *  \throw CommandDefinition::Error command arguments are invalid
+   *  \return noun, verb, arguments, execute function
    */
-  std::tuple<Execute*, CommandArguments>
+  std::tuple<std::string, std::string, CommandArguments, ExecuteCommand>
   parse(const std::vector<std::string>& tokens, ParseMode mode) const;
 
 private:
@@ -100,7 +100,7 @@
   struct Command
   {
     CommandDefinition def;
-    Execute execute;
+    ExecuteCommand execute;
     AvailableIn modes;
   };
 
diff --git a/tools/nfdc/execute-command.hpp b/tools/nfdc/execute-command.hpp
new file mode 100644
index 0000000..31b2d52
--- /dev/null
+++ b/tools/nfdc/execute-command.hpp
@@ -0,0 +1,62 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD 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.
+ *
+ * NFD 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
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_TOOLS_NFDC_EXECUTE_COMMAND_HPP
+#define NFD_TOOLS_NFDC_EXECUTE_COMMAND_HPP
+
+#include "command-arguments.hpp"
+#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/security/key-chain.hpp>
+
+namespace nfd {
+namespace tools {
+namespace nfdc {
+
+using ndn::Face;
+using ndn::KeyChain;
+
+/** \brief context for command execution
+ */
+struct ExecuteContext
+{
+  const std::string& noun;
+  const std::string& verb;
+  const CommandArguments& args;
+
+  Face& face;
+  KeyChain& keyChain;
+  ///\todo validator
+};
+
+/** \brief a function to execute a command
+ *  \return exit code
+ */
+typedef std::function<int(ExecuteContext& ctx)> ExecuteCommand;
+
+} // namespace nfdc
+} // namespace tools
+} // namespace nfd
+
+#endif // NFD_TOOLS_NFDC_EXECUTE_COMMAND_HPP
diff --git a/tools/nfdc/legacy-nfdc.cpp b/tools/nfdc/legacy-nfdc.cpp
index 5b7ff45..f5c4fa7 100644
--- a/tools/nfdc/legacy-nfdc.cpp
+++ b/tools/nfdc/legacy-nfdc.cpp
@@ -38,14 +38,14 @@
 const time::milliseconds LegacyNfdc::DEFAULT_EXPIRATION_PERIOD = time::milliseconds::max();
 const uint64_t LegacyNfdc::DEFAULT_COST = 0;
 
-LegacyNfdc::LegacyNfdc(ndn::Face& face)
+LegacyNfdc::LegacyNfdc(Face& face, KeyChain& keyChain)
   : m_flags(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT)
   , m_cost(DEFAULT_COST)
   , m_origin(ndn::nfd::ROUTE_ORIGIN_STATIC)
   , m_expires(DEFAULT_EXPIRATION_PERIOD)
   , m_facePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT)
   , m_face(face)
-  , m_controller(face, m_keyChain)
+  , m_controller(face, keyChain)
 {
 }
 
@@ -326,11 +326,12 @@
 }
 
 int
-legacyNfdcMain(const std::string& subcommand, const std::vector<std::string>& args)
+legacyNfdcMain(ExecuteContext& ctx)
 {
-  ndn::Face face;
-  LegacyNfdc p(face);
+  LegacyNfdc p(ctx.face, ctx.keyChain);
 
+  const std::string& subcommand = ctx.noun;
+  auto args = ctx.args.get<std::vector<std::string>>("args");
   bool wantUnsetChildInherit = false;
   bool wantCapture = false;
   bool wantPermanentFace = false;
@@ -381,18 +382,12 @@
   }
   p.m_commandLineArguments = unparsed;
 
-  try {
-    bool isOk = p.dispatch(subcommand);
-    if (!isOk) {
-      legacyNfdcUsage();
-      return 1;
-    }
-    face.processEvents();
+  bool isOk = p.dispatch(subcommand);
+  if (!isOk) {
+    legacyNfdcUsage();
+    return 1;
   }
-  catch (const std::exception& e) {
-    std::cerr << "ERROR: " << e.what() << std::endl;
-    return 2;
-  }
+  ctx.face.processEvents();
   return 0;
 }
 
diff --git a/tools/nfdc/legacy-nfdc.hpp b/tools/nfdc/legacy-nfdc.hpp
index 1c3772b..9acb228 100644
--- a/tools/nfdc/legacy-nfdc.hpp
+++ b/tools/nfdc/legacy-nfdc.hpp
@@ -26,9 +26,7 @@
 #ifndef NFD_TOOLS_NFDC_LEGACY_NFDC_HPP
 #define NFD_TOOLS_NFDC_LEGACY_NFDC_HPP
 
-#include "core/common.hpp"
-#include <ndn-cxx/face.hpp>
-#include <ndn-cxx/security/key-chain.hpp>
+#include "execute-command.hpp"
 #include <ndn-cxx/mgmt/nfd/controller.hpp>
 
 namespace nfd {
@@ -51,8 +49,7 @@
     }
   };
 
-  explicit
-  LegacyNfdc(ndn::Face& face);
+  LegacyNfdc(Face& face, KeyChain& keyChain);
 
   bool
   dispatch(const std::string& cmd);
@@ -169,8 +166,7 @@
   ndn::nfd::FacePersistency m_facePersistency;
 
 private:
-  ndn::KeyChain m_keyChain;
-  ndn::Face& m_face;
+  Face& m_face;
   ndn::nfd::Controller m_controller;
 };
 
@@ -178,7 +174,7 @@
 legacyNfdcUsage();
 
 int
-legacyNfdcMain(const std::string& subcommand, const std::vector<std::string>& args);
+legacyNfdcMain(ExecuteContext& ctx);
 
 } // namespace nfdc
 } // namespace tools
diff --git a/tools/nfdc/main.cpp b/tools/nfdc/main.cpp
index 85fe1e9..c578407 100644
--- a/tools/nfdc/main.cpp
+++ b/tools/nfdc/main.cpp
@@ -48,21 +48,27 @@
 
   CommandParser parser;
   registerCommands(parser);
-  CommandParser::Execute* execute = nullptr;
+  std::string noun, verb;
   CommandArguments ca;
+  ExecuteCommand execute;
   try {
-    std::tie(execute, ca) = parser.parse(args, ParseMode::ONE_SHOT);
+    std::tie(noun, verb, ca, execute) = parser.parse(args, ParseMode::ONE_SHOT);
   }
   catch (const std::invalid_argument& e) {
     std::cerr << e.what() << std::endl;
     return 1;
   }
 
-  ///\todo create Face and KeyChain here
-  (*execute)(ca);
-  ///\todo call processEvents here
-  ///\todo return proper exit code here, instead of using exit() in subcommand
-  return 0;
+  try {
+    ndn::Face face;
+    ndn::KeyChain keyChain;
+    ExecuteContext ctx{noun, verb, ca, face, keyChain};
+    return execute(ctx);
+  }
+  catch (const std::exception& e) {
+    std::cerr << e.what() << std::endl;
+    return 1;
+  }
 }
 
 } // namespace nfdc
diff --git a/tools/nfdc/status-main.cpp b/tools/nfdc/status-main.cpp
index 0f87ab1..c39f694 100644
--- a/tools/nfdc/status-main.cpp
+++ b/tools/nfdc/status-main.cpp
@@ -114,7 +114,7 @@
 }
 
 int
-statusMain(const std::vector<std::string>& args)
+statusMain(const std::vector<std::string>& args, Face& face, KeyChain& keyChain)
 {
   int exitCode = -1;
   Options options;
@@ -123,8 +123,6 @@
     return exitCode;
   }
 
-  Face face;
-  KeyChain keyChain;
   unique_ptr<Validator> validator = make_unique<ndn::ValidatorNull>();
   CommandOptions ctrlOptions;
 
diff --git a/tools/nfdc/status-main.hpp b/tools/nfdc/status-main.hpp
index 62b58a6..8294a2c 100644
--- a/tools/nfdc/status-main.hpp
+++ b/tools/nfdc/status-main.hpp
@@ -26,14 +26,14 @@
 #ifndef NFD_TOOLS_NFDC_STATUS_MAIN_HPP
 #define NFD_TOOLS_NFDC_STATUS_MAIN_HPP
 
-#include "core/common.hpp"
+#include "execute-command.hpp"
 
 namespace nfd {
 namespace tools {
 namespace nfdc {
 
 int
-statusMain(const std::vector<std::string>& args);
+statusMain(const std::vector<std::string>& args, Face& face, KeyChain& keyChain);
 
 } // namespace nfdc
 } // namespace tools