enable published data validation

add flag to indicate the last component for autocompletion

Change-Id: Ice97969b2043dd0e15d00576e605d19a7528f21d
diff --git a/catalog/src/publish/publish-adapter.hpp b/catalog/src/publish/publish-adapter.hpp
index 1d6f91f..c331bf7 100644
--- a/catalog/src/publish/publish-adapter.hpp
+++ b/catalog/src/publish/publish-adapter.hpp
@@ -215,8 +215,11 @@
   onFetchUpdateDataTimeout(const ndn::Interest& interest);
 
   void
-  onUpdateValidationFailed(const std::shared_ptr<const ndn::Data>& data,
-                           const std::string& failureInfo);
+  onValidationFailed(const std::shared_ptr<const ndn::Data>& data,
+                     const std::string& failureInfo);
+
+  void
+  validatePublishedDataPaylod(const std::shared_ptr<const ndn::Data>& data);
 
 protected:
   typedef std::unordered_map<ndn::Name, const ndn::RegisteredPrefixId*> RegisteredPrefixList;
@@ -496,9 +499,9 @@
   retrieveInterest->setInterestLifetime(ndn::time::milliseconds(4000));
   retrieveInterest->setMustBeFresh(m_mustBeFresh);
   m_face->expressInterest(*retrieveInterest,
-                          bind(&publish::PublishAdapter<DatabaseHandler>::onPublishedData,
+                          bind(&PublishAdapter<DatabaseHandler>::onPublishedData,
                                this,_1, _2),
-                          bind(&publish::PublishAdapter<DatabaseHandler>::onTimeout, this, _1));
+                          bind(&PublishAdapter<DatabaseHandler>::onTimeout, this, _1));
   std::cout << "Expressing Interest for: " << retrieveInterest->toUri() << std::endl;
 }
 
@@ -511,6 +514,14 @@
 
 template <typename DatabaseHandler>
 void
+PublishAdapter<DatabaseHandler>::onValidationFailed(const std::shared_ptr<const ndn::Data>& data,
+                                                    const std::string& failureInfo)
+{
+  std::cout << "Validation failed: " << data->getName() << failureInfo << std::endl;
+}
+
+template <typename DatabaseHandler>
+void
 PublishAdapter<DatabaseHandler>::onPublishedData(const ndn::Interest& interest,
                                                  const ndn::Data& data)
 {
@@ -518,38 +529,46 @@
   if (data.getContent().empty()) {
     return;
   }
+  m_publishValidator->validate(data,
+                               bind(&PublishAdapter<DatabaseHandler>::validatePublishedDataPaylod, this, _1),
+                               bind(&PublishAdapter<DatabaseHandler>::onValidationFailed, this, _1, _2));
+}
 
-  std::shared_ptr<ndn::Data> dataPtr = std::make_shared<ndn::Data>(data);
+template <typename DatabaseHandler>
+void
+PublishAdapter<DatabaseHandler>::validatePublishedDataPaylod(const ndn::shared_ptr<const ndn::Data>& data)
+{
   // validate published data payload, if failed, return
-  if (!validatePublicationChanges(dataPtr)) {
-    std::cout << "data validation failed : " << dataPtr->getName() << std::endl;
+  if (!validatePublicationChanges(data)) {
+    std::cout << "data validation failed : " << data->getName() << std::endl;
 #ifndef NDEBUG
-    const std::string payload(reinterpret_cast<const char*>(dataPtr->getContent().value()),
-                              dataPtr->getContent().value_size());
+    const std::string payload(reinterpret_cast<const char*>(data->getContent().value()),
+                              data->getContent().value_size());
     std::cout << payload << std::endl;
 #endif
     return;
   }
 
   // todo: return value to indicate if the insertion succeeds
-  processUpdateData(dataPtr);
+  processUpdateData(data);
 
   // ideally, data should not be stale?
-  m_socket->publishData(data.getContent(), ndn::time::seconds(3600));
+  m_socket->publishData(data->getContent(), ndn::time::seconds(3600));
 
   // if this is not the final block, continue to fetch the next one
-  const ndn::name::Component& finalBlockId = data.getMetaInfo().getFinalBlockId();
-  if (finalBlockId == data.getName()[-1]) {
+  const ndn::name::Component& finalBlockId = data->getMetaInfo().getFinalBlockId();
+  if (finalBlockId == data->getName()[-1]) {
     m_isFinished = true;
   }
   //else, get the next segment
   if (!m_isFinished) {
-    ndn::Name nextInterestName = data.getName().getPrefix(-1);
-    uint64_t incomingSegment = data.getName()[-1].toSegment();
-    std::cout << " Next Interest Name " << nextInterestName << " Segment " << incomingSegment++
+    ndn::Name nextInterestName = data->getName().getPrefix(-1);
+    uint64_t incomingSegment = data->getName()[-1].toSegment();
+    incomingSegment++;
+    std::cout << " Next Interest Name " << nextInterestName << " Segment " << incomingSegment
               << std::endl;
     std::shared_ptr<ndn::Interest> nextInterest =
-      std::make_shared<ndn::Interest>(nextInterestName.appendSegment(incomingSegment++));
+      std::make_shared<ndn::Interest>(nextInterestName.appendSegment(incomingSegment));
     nextInterest->setInterestLifetime(ndn::time::milliseconds(4000));
     nextInterest->setMustBeFresh(m_mustBeFresh);
     m_face->expressInterest(*nextInterest,
@@ -697,15 +716,6 @@
 
 template <typename DatabaseHandler>
 void
-PublishAdapter<DatabaseHandler>::onUpdateValidationFailed(const
-                                                          std::shared_ptr<const ndn::Data>& data,
-                                                          const std::string& failureInfo)
-{
-  std::cout << "failed to validate Data" << data->getName() << " : " << failureInfo << std::endl;
-}
-
-template <typename DatabaseHandler>
-void
 PublishAdapter<DatabaseHandler>::processSyncUpdate(const std::vector<chronosync::MissingDataInfo>&
                                                    updates)
 {
@@ -725,7 +735,7 @@
       if (seq > localSeqNo) {
         m_socket->fetchData(updates[i].session, seq,
                             bind(&PublishAdapter<DatabaseHandler>::processUpdateData,this, _1),
-                            bind(&PublishAdapter<DatabaseHandler>::onUpdateValidationFailed,
+                            bind(&PublishAdapter<DatabaseHandler>::onValidationFailed,
                                  this, _1, _2),
                             bind(&PublishAdapter<DatabaseHandler>::onFetchUpdateDataTimeout,
                                  this, _1),
diff --git a/catalog/src/query/query-adapter.hpp b/catalog/src/query/query-adapter.hpp
index 2b85da5..0a5ae0b 100644
--- a/catalog/src/query/query-adapter.hpp
+++ b/catalog/src/query/query-adapter.hpp
@@ -144,6 +144,8 @@
    * @param resultCount:    the number of records in the query results
    * @param viewStart:      the start index of the record in the query results payload
    * @param viewEnd:        the end index of the record in the query results payload
+   * @param lastComponent:  flag to indicate the content contains the last component for
+                            autocompletion query
    */
   std::shared_ptr<ndn::Data>
   makeReplyData(const ndn::Name& segmentPrefix,
@@ -153,7 +155,8 @@
                 bool isAutocomplete,
                 uint64_t resultCount,
                 uint64_t viewStart,
-                uint64_t viewEnd);
+                uint64_t viewEnd,
+                bool lastComponent);
 
   /**
    * Helper function that generates query results from a Json query carried in the Interest
@@ -202,7 +205,8 @@
   virtual void
   prepareSegments(const ndn::Name& segmentPrefix,
                   const std::string& sqlString,
-                  bool autocomplete);
+                  bool autocomplete,
+                  bool lastComponent);
 
   /**
    * Helper function to set the DatabaseHandler
@@ -221,12 +225,14 @@
 
   /**
    * Helper function that generates the sqlQuery string for autocomplete query
-   * @param sqlQuery:     stringstream to save the sqlQuery string
-   * @param jsonValue:    Json value that contains the query information
+   * @param sqlQuery:      stringstream to save the sqlQuery string
+   * @param jsonValue:     Json value that contains the query information
+   * @param lastComponent: Flag to mark the last component query
    */
   bool
   json2AutocompletionSql(std::stringstream& sqlQuery,
-                         Json::Value& jsonValue);
+                         Json::Value& jsonValue,
+                         bool& lastComponent);
 
   bool
   json2PrefixBasedSearchSql(std::stringstream& sqlQuery,
@@ -738,7 +744,8 @@
 template <typename DatabaseHandler>
 bool
 QueryAdapter<DatabaseHandler>::json2AutocompletionSql(std::stringstream& sqlQuery,
-                                                      Json::Value& jsonValue)
+                                                      Json::Value& jsonValue,
+                                                      bool& lastComponent)
 {
 #ifndef NDEBUG
   std::cout << "jsonValue in json2AutocompletionSql: " << jsonValue.toStyledString() << std::endl;
@@ -797,6 +804,9 @@
 
   // 2. generate the sql string (append what appears in the typed string, like activity='xxx'),
   // return true
+  if (count == m_nameFields.size() - 1)
+    lastComponent = true; // indicate this query is to query the last component
+
   bool more = false;
   sqlQuery << "SELECT DISTINCT " << m_nameFields[count] << " FROM " << m_databaseTable;
   for (std::map<std::string, std::string>::iterator it = typedComponents.begin();
@@ -967,7 +977,7 @@
   m_mutex.unlock();
 
   // 3) Convert the JSON Query into a MySQL one
-  bool autocomplete = false;
+  bool autocomplete = false, lastComponent = false;
   std::stringstream sqlQuery;
 
   ndn::Name segmentPrefix(getQueryResultsName(interest, version));
@@ -977,7 +987,7 @@
   // if JSON::Value contains ? as key, is autocompletion
   if (parsedFromString.get("?", tmp) != tmp) {
     autocomplete = true;
-    if (!json2AutocompletionSql(sqlQuery, parsedFromString)) {
+    if (!json2AutocompletionSql(sqlQuery, parsedFromString, lastComponent)) {
       sendNack(segmentPrefix);
       return;
     }
@@ -996,14 +1006,15 @@
   }
 
   // 4) Run the Query
-  prepareSegments(segmentPrefix, sqlQuery.str(), autocomplete);
+  prepareSegments(segmentPrefix, sqlQuery.str(), autocomplete, lastComponent);
 }
 
 template <typename DatabaseHandler>
 void
 QueryAdapter<DatabaseHandler>::prepareSegments(const ndn::Name& segmentPrefix,
                                                const std::string& sqlString,
-                                               bool autocomplete)
+                                               bool autocomplete,
+                                               bool lastComponent)
 {
   // empty
 }
@@ -1013,7 +1024,8 @@
 void
 QueryAdapter<MYSQL>::prepareSegments(const ndn::Name& segmentPrefix,
                                      const std::string& sqlString,
-                                     bool autocomplete)
+                                     bool autocomplete,
+                                     bool lastComponent)
 {
 #ifndef NDEBUG
   std::cout << "prepareSegments() executes sql : " << sqlString << std::endl;
@@ -1057,7 +1069,7 @@
     if (tmpString.length() > PAYLOAD_LIMIT) {
       std::shared_ptr<ndn::Data> data
         = makeReplyData(segmentPrefix, resultJson, segmentNo, false,
-                        autocomplete, resultCount, viewStart, viewEnd);
+                        autocomplete, resultCount, viewStart, viewEnd, lastComponent);
       m_mutex.lock();
       m_cache.insert(*data);
       m_mutex.unlock();
@@ -1072,7 +1084,7 @@
 
   std::shared_ptr<ndn::Data> data
     = makeReplyData(segmentPrefix, resultJson, segmentNo, true,
-                    autocomplete, resultCount, viewStart, viewEnd);
+                    autocomplete, resultCount, viewStart, viewEnd, lastComponent);
   m_mutex.lock();
   m_cache.insert(*data);
   m_mutex.unlock();
@@ -1087,7 +1099,8 @@
                                              bool isAutocomplete,
                                              uint64_t resultCount,
                                              uint64_t viewStart,
-                                             uint64_t viewEnd)
+                                             uint64_t viewEnd,
+                                             bool lastComponent)
 {
   Json::Value entry;
   Json::FastWriter fastWriter;
@@ -1096,6 +1109,9 @@
   entry["viewStart"] = Json::UInt64(viewStart);
   entry["viewEnd"] = Json::UInt64(viewEnd);
 
+  if (lastComponent)
+    entry["lastComponent"] = Json::Value(true);
+
 #ifndef NDEBUG
   std::cout << "resultCount " << resultCount
             << "; viewStart " << viewStart