meta-info: allow typed name component in FinalBlockId

refs #4526

Change-Id: I3b6667928fa47c631e45ff5f0ca2c5030c5cc2ad
diff --git a/src/data.cpp b/src/data.cpp
index 9a59089..6b50dca 100644
--- a/src/data.cpp
+++ b/src/data.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2017 Regents of the University of California.
+ * Copyright (c) 2013-2018 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -246,7 +246,7 @@
 }
 
 Data&
-Data::setFreshnessPeriod(const time::milliseconds& freshnessPeriod)
+Data::setFreshnessPeriod(time::milliseconds freshnessPeriod)
 {
   resetWire();
   m_metaInfo.setFreshnessPeriod(freshnessPeriod);
@@ -254,6 +254,20 @@
 }
 
 Data&
+Data::setFinalBlock(optional<name::Component> finalBlockId)
+{
+  resetWire();
+  m_metaInfo.setFinalBlock(std::move(finalBlockId));
+  return *this;
+}
+
+name::Component
+Data::getFinalBlockId() const
+{
+  return m_metaInfo.getFinalBlockId();
+}
+
+Data&
 Data::setFinalBlockId(const name::Component& finalBlockId)
 {
   resetWire();
diff --git a/src/data.hpp b/src/data.hpp
index e0a8466..8eb1b3d 100644
--- a/src/data.hpp
+++ b/src/data.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2017 Regents of the University of California.
+ * Copyright (c) 2013-2018 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -206,22 +206,36 @@
   Data&
   setContentType(uint32_t type);
 
-  const time::milliseconds&
+  time::milliseconds
   getFreshnessPeriod() const
   {
     return m_metaInfo.getFreshnessPeriod();
   }
 
   Data&
-  setFreshnessPeriod(const time::milliseconds& freshnessPeriod);
+  setFreshnessPeriod(time::milliseconds freshnessPeriod);
 
-  const name::Component&
-  getFinalBlockId() const
+  const optional<name::Component>&
+  getFinalBlock() const
   {
-    return m_metaInfo.getFinalBlockId();
+    return m_metaInfo.getFinalBlock();
   }
 
   Data&
+  setFinalBlock(optional<name::Component> finalBlockId);
+
+  /** @deprecated Use @c getFinalBlock
+   *  @sa MetaInfo::getFinalBlockId
+   */
+  NDN_CXX_DEPRECATED
+  name::Component
+  getFinalBlockId() const;
+
+  /** @deprecated Use @c setFinalBlock
+   *  @sa MetaInfo::setFinalBlockId
+   */
+  NDN_CXX_DEPRECATED
+  Data&
   setFinalBlockId(const name::Component& finalBlockId);
 
 protected:
diff --git a/src/meta-info.cpp b/src/meta-info.cpp
index e19c11d..c6a43a4 100644
--- a/src/meta-info.cpp
+++ b/src/meta-info.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2017 Regents of the University of California.
+ * Copyright (c) 2013-2018 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -63,13 +63,22 @@
 }
 
 MetaInfo&
-MetaInfo::setFinalBlockId(const name::Component& finalBlockId)
+MetaInfo::setFinalBlock(optional<name::Component> finalBlockId)
 {
   m_wire.reset();
-  m_finalBlockId = finalBlockId;
+  m_finalBlockId = std::move(finalBlockId);
   return *this;
 }
 
+MetaInfo&
+MetaInfo::setFinalBlockId(const name::Component& finalBlockId)
+{
+  if (finalBlockId.isGeneric() && finalBlockId.empty()) {
+    return setFinalBlock(nullopt);
+  }
+  return setFinalBlock(finalBlockId);
+}
+
 const std::list<Block>&
 MetaInfo::getAppMetaInfo() const
 {
@@ -146,8 +155,8 @@
   }
 
   // FinalBlockId
-  if (!m_finalBlockId.empty()) {
-    totalLength += prependNestedBlock(encoder, tlv::FinalBlockId, m_finalBlockId);
+  if (m_finalBlockId) {
+    totalLength += prependNestedBlock(encoder, tlv::FinalBlockId, *m_finalBlockId);
   }
 
   // FreshnessPeriod
@@ -218,16 +227,11 @@
 
   // FinalBlockId
   if (val != m_wire.elements_end() && val->type() == tlv::FinalBlockId) {
-    m_finalBlockId = val->blockFromValue();
-    if (m_finalBlockId.type() != tlv::NameComponent)
-      {
-        /// @todo May or may not throw exception later...
-        m_finalBlockId = name::Component();
-      }
+    m_finalBlockId.emplace(val->blockFromValue());
     ++val;
   }
   else {
-    m_finalBlockId = name::Component();
+    m_finalBlockId = nullopt;
   }
 
   // AppMetaInfo (if any)
@@ -248,9 +252,9 @@
   }
 
   // FinalBlockId
-  if (!info.getFinalBlockId().empty()) {
+  if (info.getFinalBlock()) {
     os << ", FinalBlockId: ";
-    info.getFinalBlockId().toUri(os);
+    info.getFinalBlock()->toUri(os);
   }
 
   // App-defined MetaInfo items
diff --git a/src/meta-info.hpp b/src/meta-info.hpp
index e8e8a00..911b1a3 100644
--- a/src/meta-info.hpp
+++ b/src/meta-info.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2017 Regents of the University of California.
+ * Copyright (c) 2013-2018 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -87,27 +87,71 @@
   wireDecode(const Block& wire);
 
 public: // getter/setter
+  /** @brief return ContentType
+   *
+   *  If ContentType element is omitted, returns \c tlv::ContentType_Blob.
+   */
   uint32_t
-  getType() const;
+  getType() const
+  {
+    return m_type;
+  }
 
   /** @brief set ContentType
-   *  @param type a code defined in tlv::ContentTypeValue
+   *  @param type a number defined in \c tlv::ContentTypeValue
    */
   MetaInfo&
   setType(uint32_t type);
 
-  const time::milliseconds&
-  getFreshnessPeriod() const;
+  /** @brief return FreshnessPeriod
+   *
+   *  If FreshnessPeriod element is omitted, returns \c DEFAULT_FRESHNESS_PERIOD.
+   */
+  time::milliseconds
+  getFreshnessPeriod() const
+  {
+    return m_freshnessPeriod;
+  }
 
   /** @brief set FreshnessPeriod
-   *  @throw std::invalid_argument specified FreshnessPeriod is < 0
+   *  @throw std::invalid_argument specified FreshnessPeriod is negative
    */
   MetaInfo&
   setFreshnessPeriod(time::milliseconds freshnessPeriod);
 
-  const name::Component&
-  getFinalBlockId() const;
+  /** @brief return FinalBlockId
+   */
+  const optional<name::Component>&
+  getFinalBlock() const
+  {
+    return m_finalBlockId;
+  }
 
+  /** @brief set FinalBlockId
+   */
+  MetaInfo&
+  setFinalBlock(optional<name::Component> finalBlockId);
+
+  /** @brief return FinalBlockId
+   *  @deprecated use @c getFinalBlock
+   *
+   *  If FinalBlockId element is omitted, returns a default-constructed @c name::Component.
+   *  This is indistinguishable from having an empty GenericNameComponent as FinalBlockId.
+   */
+  NDN_CXX_DEPRECATED
+  name::Component
+  getFinalBlockId() const
+  {
+    return getFinalBlock().value_or(name::Component());
+  }
+
+  /** @brief set FinalBlockId
+   *  @deprecated use @c setFinalBlock
+   *
+   *  Passing a default-constructed @c name::Component removes FinalBlockId element.
+   *  This API does not support adding an empty GenericNameComponent as FinalBlockId.
+   */
+  NDN_CXX_DEPRECATED
   MetaInfo&
   setFinalBlockId(const name::Component& finalBlockId);
 
@@ -117,7 +161,7 @@
    *
    * @note Warning: Experimental API, which may change or disappear in the future
    *
-   * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlockId
+   * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlock
    *       is called before *AppMetaInfo, all app-defined blocks will be lost
    */
   const std::list<Block>&
@@ -133,7 +177,7 @@
    *
    * @note Warning: Experimental API, which may change or disappear in the future
    *
-   * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlockId
+   * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlock
    *       is called before *AppMetaInfo, all app-defined blocks will be lost
    */
   MetaInfo&
@@ -147,7 +191,7 @@
    *
    * @note Warning: Experimental API, which may change or disappear in the future
    *
-   * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlockId
+   * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlock
    *       is called before *AppMetaInfo, all app-defined blocks will be lost
    */
   MetaInfo&
@@ -160,7 +204,7 @@
    *
    * @note Warning: Experimental API, which may change or disappear in the future
    *
-   * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlockId
+   * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlock
    *       is called before *AppMetaInfo, all app-defined blocks will be lost
    */
   bool
@@ -176,7 +220,7 @@
    *
    * @note Warning: Experimental API, which may change or disappear in the future
    *
-   * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlockId
+   * @note If MetaInfo is decoded from wire and setType, setFreshnessPeriod, or setFinalBlock
    *       is called before *AppMetaInfo, all app-defined blocks will be lost
    */
   const Block*
@@ -192,7 +236,7 @@
 private:
   uint32_t m_type;
   time::milliseconds m_freshnessPeriod;
-  name::Component m_finalBlockId;
+  optional<name::Component> m_finalBlockId;
   std::list<Block> m_appMetaInfo;
 
   mutable Block m_wire;
@@ -203,24 +247,6 @@
 std::ostream&
 operator<<(std::ostream& os, const MetaInfo& info);
 
-inline uint32_t
-MetaInfo::getType() const
-{
-  return m_type;
-}
-
-inline const time::milliseconds&
-MetaInfo::getFreshnessPeriod() const
-{
-  return m_freshnessPeriod;
-}
-
-inline const name::Component&
-MetaInfo::getFinalBlockId() const
-{
-  return m_finalBlockId;
-}
-
 inline bool
 MetaInfo::operator==(const MetaInfo& other) const
 {
diff --git a/src/mgmt/dispatcher.cpp b/src/mgmt/dispatcher.cpp
index df27aca..2a14a91 100644
--- a/src/mgmt/dispatcher.cpp
+++ b/src/mgmt/dispatcher.cpp
@@ -313,7 +313,7 @@
 
   MetaInfo metaInfo;
   if (isFinalBlock) {
-    metaInfo.setFinalBlockId(dataName[-1]);
+    metaInfo.setFinalBlock(dataName[-1]);
   }
 
   sendData(dataName, content, metaInfo, destination, imsFresh);
diff --git a/src/security/v2/certificate-bundle-fetcher.cpp b/src/security/v2/certificate-bundle-fetcher.cpp
index e2fdab9..45a0c38 100644
--- a/src/security/v2/certificate-bundle-fetcher.cpp
+++ b/src/security/v2/certificate-bundle-fetcher.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2017 Regents of the University of California.
+/*
+ * Copyright (c) 2013-2018 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -160,9 +160,9 @@
   else {
     state->setTag(make_shared<BundleNameTag>(bundleData.getName()));
 
-    const name::Component& finalBlockId = bundleData.getMetaInfo().getFinalBlockId();
-    if (!finalBlockId.empty()) {
-      state->setTag(make_shared<FinalBlockIdTag>(finalBlockId));
+    const auto& finalBlockId = bundleData.getFinalBlock();
+    if (!finalBlockId) {
+      state->setTag(make_shared<FinalBlockIdTag>(*finalBlockId));
     }
 
     Block bundleContent = bundleData.getContent();
diff --git a/src/util/segment-fetcher.cpp b/src/util/segment-fetcher.cpp
index b23b991..90cddaf 100644
--- a/src/util/segment-fetcher.cpp
+++ b/src/util/segment-fetcher.cpp
@@ -131,8 +131,8 @@
       m_buffer->write(reinterpret_cast<const char*>(data.getContent().value()),
                       data.getContent().value_size());
       afterSegmentValidated(data);
-      const name::Component& finalBlockId = data.getMetaInfo().getFinalBlockId();
-      if (finalBlockId.empty() || (finalBlockId > currentSegment)) {
+      const auto& finalBlockId = data.getFinalBlock();
+      if (!finalBlockId || (*finalBlockId > currentSegment)) {
         fetchNextSegment(origInterest, data.getName(), currentSegment.toSegment() + 1, self);
       }
       else {