catalog: Implement Sync Update Executor

Change-Id: I88a0c6935d7b8094dfb587e83270a607e753ea31
refs: #2611
diff --git a/tools/cxx-producer.cpp b/tools/cxx-producer.cpp
new file mode 100644
index 0000000..c0f028f
--- /dev/null
+++ b/tools/cxx-producer.cpp
@@ -0,0 +1,193 @@
+/** NDN-Atmos: Cataloging Service for distributed data originally developed
+ *  for atmospheric science data
+ *  Copyright (C) 2015 Colorado State University
+ *
+ *  NDN-Atmos 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.
+ *
+ *  NDN-Atmos 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 NDN-Atmos.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/security/key-chain.hpp>
+#include <json/value.h>
+#include <json/writer.h>
+#include <json/reader.h>
+#include <iostream>
+#include <fstream>
+#include <getopt.h>
+
+void
+usage(const char *fileName)
+{
+  std::cout << "\n Usage:\n " << fileName <<
+    "[-h] [-f name list file] \n"
+    "   [-c catalogPrefix]  - set the catalog prefix\n"
+    "   [-f name list file]  - set the file that contains name list\n"
+    "   [-n namespace]       - set the publisher namespace\n"
+    "   [-h]                 - print help and exit\n"
+    "\n";
+}
+
+namespace ndn {
+namespace atmos {
+
+class Producer : noncopyable
+{
+public:
+  void
+  run()
+  {
+    if (m_jsonFile.empty()) {
+      std::cout << "jsonFile is empty! exiting ..." << std::endl;
+      return;
+    }
+    m_face.setInterestFilter(m_namespace,
+                             bind(&Producer::onInterest, this, _1, _2),
+                             bind(&Producer::onRegisterSucceed, this, _1),
+                             bind(&Producer::onRegisterFailed, this, _1, _2));
+    m_face.processEvents();
+  }
+
+private:
+  void
+  onInterest(const InterestFilter& filter, const Interest& interest)
+  {
+    std::cout << "<< I: " << interest << std::endl;
+
+    // Create new name, based on Interest's name
+    Name dataName(interest.getName());
+
+    Json::Value publishValue;   // will contains the root value after parsing.
+    Json::Reader reader;
+    std::ifstream test(m_jsonFile, std::ifstream::binary);
+    bool parsingSuccessful = reader.parse(test, publishValue, false);
+    if (!parsingSuccessful) {
+        // report to the user the failure and their locations in the document.
+        std::cout << reader.getFormattedErrorMessages() << std::endl;
+    }
+
+    Json::FastWriter fastWriter;
+    const std::string jsonMessage = fastWriter.write(publishValue);
+    const char* payload = jsonMessage.c_str();
+    size_t payLoadLength = jsonMessage.size() + 1;
+
+    // Create Data packet
+    shared_ptr<Data> data = make_shared<Data>();
+    data->setName(dataName);
+    data->setFreshnessPeriod(time::seconds(10));
+    // todo: set the correct segment number
+    // assume that the last component it the segment number
+    data->setFinalBlockId(interest.getName()[-1]);
+    data->setContent(reinterpret_cast<const uint8_t*>(payload), payLoadLength);
+
+    // Sign Data packet with default identity
+    m_keyChain.sign(*data);
+
+    // Return Data packet to the requester
+    std::cout << ">> D: " << *data << std::endl;
+    m_face.put(*data);
+    m_face.shutdown();
+  }
+
+
+  void
+  onRegisterFailed(const Name& prefix, const std::string& reason)
+  {
+    std::cerr << "ERROR: Failed to register prefix \""
+              << prefix << "\" in local hub's daemon (" << reason << ")"
+              << std::endl;
+    m_face.shutdown();
+  }
+
+  void
+  onRegisterSucceed(const Name& prefix)
+  {
+    std::cout << "register succeed" << std::endl;
+    Interest interest(Name(m_catalogPrefix).append("publish").append(m_namespace));
+    interest.setInterestLifetime(time::milliseconds(1000));
+    interest.setMustBeFresh(true);
+
+    m_face.expressInterest(interest,
+                           bind(&Producer::onData, this,  _1, _2),
+                           bind(&Producer::onTimeout, this, _1));
+
+    std::cout << "Sending " << interest << std::endl;
+  }
+
+  void
+  onData(const Interest& interest, const Data& data)
+  {
+    std::cout << data << std::endl;
+  }
+
+  void
+  onTimeout(const Interest& interest)
+  {
+    std::cout << "Timeout " << interest << std::endl;
+  }
+
+public:
+  std::string m_jsonFile;
+  std::string m_namespace;
+  std::string m_catalogPrefix;
+
+private:
+  Face m_face;
+  KeyChain m_keyChain;
+};
+
+}
+}
+
+int
+main(int argc, char** argv)
+{
+  ndn::atmos::Producer producer;
+  int option;
+  if (argc < 7) {
+    usage(argv[0]);
+    return 0;
+  }
+
+  while ((option = getopt(argc, argv, "c:f:n:h")) != -1) {
+    switch (option) {
+      case 'c':
+        producer.m_catalogPrefix.assign(optarg);
+        break;
+      case 'f':
+        producer.m_jsonFile.assign(optarg);
+        break;
+      case 'n':
+        producer.m_namespace.assign(optarg);
+        break;
+      case 'h':
+      default:
+        usage(argv[0]);
+        return 0;
+    }
+  }
+
+  argc -= optind;
+  argv += optind;
+  if (argc != 0) {
+    usage(argv[0]);
+    return 1;
+  }
+
+  try {
+    producer.run();
+  }
+  catch (const std::exception& e) {
+    std::cerr << "ERROR: " << e.what() << std::endl;
+  }
+  return 0;
+}
diff --git a/tools/publish-files.json.example b/tools/publish-files.json.example
new file mode 100644
index 0000000..28727cd
--- /dev/null
+++ b/tools/publish-files.json.example
@@ -0,0 +1,5 @@
+{
+    "add": ["/CMIP5/t/t/t/t/t/t/t/t/t8-11"],
+    "remove": ["/CMIP5/a/b/c/d/e/f/g/h/i",
+               "/CMIP5/1/2/3/4/5/6/7/8/9"]
+}
diff --git a/tools/wscript b/tools/wscript
index 659d07c..ade7a63 100644
--- a/tools/wscript
+++ b/tools/wscript
@@ -35,7 +35,7 @@
         bld(features=['cxx', 'cxxprogram'],
             target="../bin/%s" % name,
             source=[i] + bld.path.ant_glob(['%s/**/*.cpp' % name]),
-            use='NDN_CXX'
+            use='NDN_CXX JSON'
             )
 
     # List all directories files (tool can has multiple .cpp in the directory)