move callbacks from CaModule to each CaItem

Change-Id: I8e8bef0997c6826f6f007f7ad7156957cc2fcd72
diff --git a/src/ca-config.hpp b/src/ca-config.hpp
index b80558c..2192248 100644
--- a/src/ca-config.hpp
+++ b/src/ca-config.hpp
@@ -28,6 +28,28 @@
 namespace ndn {
 namespace ndncert {
 
+/**
+ * @brief The function should be able to convert a probe info string to an identity name
+ *
+ * The function should throw exceptions when there is an unexpected input.
+ */
+using ProbeHandler = function<std::string/*identity name*/ (const std::string&/*requester input*/)>;
+
+/**
+ * @brief The function should recommend a CA plus an identity name from the given list
+ *        based on LIST additional info
+ *
+ * The function should throw exceptions when there is an unexpected input.
+ */
+using RecommendCaHandler = function<std::tuple<Name/*CA name*/, std::string/*identity*/>
+                                    (const std::string&/*requester input*/,
+                                     const std::list<Name>&/*related CA list*/)>;
+
+/**
+ * @brief The function would be invoked whenever the certificate request gets update
+ */
+using RequestUpdateCallback = function<void (const CertificateRequest&/*the latest request info*/)>;
+
 class CaItem
 {
 public:
@@ -46,6 +68,11 @@
   std::string m_probe;
   std::string m_targetedList;
   std::string m_caInfo;
+
+  // callbacks
+  ProbeHandler m_probeHandler;
+  RecommendCaHandler m_recommendCaHandler;
+  RequestUpdateCallback m_requestUpdateCallback;
 };
 
 /**
diff --git a/src/ca-module.cpp b/src/ca-module.cpp
index 904886d..38b23b8 100644
--- a/src/ca-module.cpp
+++ b/src/ca-module.cpp
@@ -40,14 +40,6 @@
   m_config.load(configPath);
   m_storage = CaStorage::createCaStorage(storageType);
 
-  // set default handler and callback
-  m_probeHandler = [&] (const std::string& probeInfo) {
-    return probeInfo;
-  };
-  m_requestUpdateCallback = [&] (const CertificateRequest& CertRequest) {
-    // do nothing
-  };
-
   // register prefix
   for (const auto& item : m_config.m_caItems) {
     Name prefix = item.m_caName;
@@ -103,18 +95,53 @@
 }
 
 void
+CaModule::setProbeHandler(const Name caName, const ProbeHandler& handler)
+{
+  for (auto& entry : m_config.m_caItems) {
+    if (entry.m_caName == caName) {
+      entry.m_probeHandler = handler;
+    }
+  }
+}
+
+void
+CaModule::setRecommendCaHandler(const Name caName, const RecommendCaHandler& handler)
+{
+  for (auto& entry : m_config.m_caItems) {
+    if (entry.m_caName == caName) {
+      entry.m_recommendCaHandler = handler;
+    }
+  }
+}
+
+void
+CaModule::setRequestUpdateCallback(const Name caName, const RequestUpdateCallback& onUpateCallback)
+{
+  for (auto& entry : m_config.m_caItems) {
+    if (entry.m_caName == caName) {
+      entry.m_requestUpdateCallback = onUpateCallback;
+    }
+  }
+}
+
+void
 CaModule::handleProbe(const Interest& request, const CaItem& caItem)
 {
   // PROBE Naming Convention: /CA-prefix/CA/_PROBE/<Probe Information>
   _LOG_TRACE("Handle PROBE request");
 
   std::string identifier;
-  try {
-    identifier = m_probeHandler(readString(request.getName().at(caItem.m_caName.size() + 2)));
+  if (caItem.m_probeHandler) {
+    try {
+      identifier = caItem.m_probeHandler(readString(request.getName().at(caItem.m_caName.size() + 2)));
+    }
+    catch (const std::exception& e) {
+      _LOG_TRACE("Cannot generate identifier for PROBE request " << e.what());
+      return;
+    }
   }
-  catch (const std::exception& e) {
-    _LOG_TRACE("Cannot generate identifier for PROBE request " << e.what());
-    return;
+  else {
+    identifier = readString(request.getName().at(caItem.m_caName.size() + 2));
   }
   Name identityName = caItem.m_caName;
   identityName.append(identifier);
@@ -170,7 +197,9 @@
   m_keyChain.sign(result, signingByIdentity(caItem.m_caName));
   m_face.put(result);
 
-  m_requestUpdateCallback(certRequest);
+  if (caItem.m_requestUpdateCallback) {
+    caItem.m_requestUpdateCallback(certRequest);
+  }
 }
 
 void
@@ -224,7 +253,9 @@
   m_keyChain.sign(result, signingByIdentity(caItem.m_caName));
   m_face.put(result);
 
-  m_requestUpdateCallback(certRequest);
+  if (caItem.m_requestUpdateCallback) {
+    caItem.m_requestUpdateCallback(certRequest);
+  }
 }
 
 void
@@ -269,7 +300,9 @@
   m_keyChain.sign(result, signingByIdentity(caItem.m_caName));
   m_face.put(result);
 
-  m_requestUpdateCallback(certRequest);
+  if (caItem.m_requestUpdateCallback) {
+    caItem.m_requestUpdateCallback(certRequest);
+  }
 
   if (certRequest.getStatus() == ChallengeModule::SUCCESS) {
     issueCertificate(certRequest, caItem);
diff --git a/src/ca-module.hpp b/src/ca-module.hpp
index 5388fe6..7e3a5e6 100644
--- a/src/ca-module.hpp
+++ b/src/ca-module.hpp
@@ -40,18 +40,6 @@
     using std::runtime_error::runtime_error;
   };
 
-  /**
-   * @brief The function should be able to convert a probe info string to an identity name
-   *
-   * The function should throw exceptions when there is an unexpected probe info.
-   */
-  using ProbeHandler = function<std::string (const std::string&)>;
-
-  /**
-   * @brief The function would be invoked whenever the certificate request gets update
-   */
-  using RequestUpdateCallback = function<void (const CertificateRequest&)>;
-
 public:
   CaModule(Face& face, security::v2::KeyChain& keyChain, const std::string& configPath,
            const std::string& storageType = "ca-storage-sqlite3");
@@ -70,18 +58,15 @@
     return m_storage;
   }
 
-  // @Deprecated This function should be set for each CA
   void
-  setProbeHandler(const ProbeHandler& handler)
-  {
-    m_probeHandler = handler;
-  }
+  setProbeHandler(const Name caName, const ProbeHandler& handler);
 
   void
-  setRequestUpdateCallback(const RequestUpdateCallback& onUpateCallback)
-  {
-    m_requestUpdateCallback = onUpateCallback;
-  }
+  setRecommendCaHandler(const Name caName, const RecommendCaHandler& handler);
+
+  void
+  setRequestUpdateCallback(const Name caName, const RequestUpdateCallback& onUpateCallback);
+
 
 PUBLIC_WITH_TESTS_ELSE_PRIVATE:
   void
@@ -123,8 +108,6 @@
   unique_ptr<CaStorage> m_storage;
   security::v2::KeyChain& m_keyChain;
 
-  ProbeHandler m_probeHandler;
-  RequestUpdateCallback m_requestUpdateCallback;
   std::list<const RegisteredPrefixId*> m_registeredPrefixIds;
   std::list<const InterestFilterId*> m_interestFilterIds;
 };
diff --git a/tests/unit-tests/ca-module.t.cpp b/tests/unit-tests/ca-module.t.cpp
index fbd7358..27cb9a7 100644
--- a/tests/unit-tests/ca-module.t.cpp
+++ b/tests/unit-tests/ca-module.t.cpp
@@ -60,8 +60,8 @@
 
   util::DummyClientFace face(m_io, {true, true});
   CaModule ca(face, m_keyChain, "tests/unit-tests/ca.conf.test");
-  ca.setProbeHandler([&] (const std::string& probeInfo) {
-      return probeInfo;
+  ca.setProbeHandler(Name("/ndn/site1"), [&] (const std::string& probeInfo) {
+      return probeInfo + "example";
     });
 
   advanceClocks(time::milliseconds(20), 60);
@@ -75,7 +75,7 @@
       count++;
       BOOST_CHECK(security::verifySignature(response, cert));
       JsonSection contentJson = ClientModule::getJsonFromData(response);
-      BOOST_CHECK_EQUAL(contentJson.get(JSON_IDNENTIFIER, ""), "/ndn/site1/zhiyi");
+      BOOST_CHECK_EQUAL(contentJson.get(JSON_IDNENTIFIER, ""), "/ndn/site1/zhiyiexample");
     });
   face.receive(interest);
 
@@ -121,9 +121,6 @@
   util::DummyClientFace face2(m_io, {true, true});
 
   CaModule ca(face, m_keyChain, "tests/unit-tests/ca.conf.test");
-  ca.setProbeHandler([&] (const std::string& probeInfo) {
-      return probeInfo;
-    });
   advanceClocks(time::milliseconds(20), 60);
 
   Name identityName("/ndn/site1");
diff --git a/tools/ndncert-ca-server.cpp b/tools/ndncert-ca-server.cpp
index c757d45..75dd400 100644
--- a/tools/ndncert-ca-server.cpp
+++ b/tools/ndncert-ca-server.cpp
@@ -56,10 +56,6 @@
   Face face;
   security::v2::KeyChain keyChain;
   CaModule ca(face, keyChain, configFilePath);
-
-  ca.setProbeHandler([&] (const std::string& probeInfo) {
-      return probeInfo;
-    });
   face.processEvents();
 
   return 0;