management: add FaceQueryFilter type

refs #2085

Change-Id: I3d2628f5738dad763baa9cd199599372aed4e23d
diff --git a/src/encoding/tlv-nfd.hpp b/src/encoding/tlv-nfd.hpp
index 9f7d5f8..91d7c11 100644
--- a/src/encoding/tlv-nfd.hpp
+++ b/src/encoding/tlv-nfd.hpp
@@ -61,9 +61,11 @@
   FaceStatus            = 128,
   LocalUri              = 129,
   ChannelStatus         = 130,
+  UriScheme             = 131,
   FaceScope             = 132,
   FacePersistency       = 133,
   LinkType              = 134,
+  FaceQueryFilter       = 150,
   FaceEventNotification = 192,
   FaceEventKind         = 193,
 
diff --git a/src/management/nfd-face-query-filter.cpp b/src/management/nfd-face-query-filter.cpp
new file mode 100644
index 0000000..39c5240
--- /dev/null
+++ b/src/management/nfd-face-query-filter.cpp
@@ -0,0 +1,344 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "nfd-face-query-filter.hpp"
+
+namespace ndn {
+namespace nfd {
+
+FaceQueryFilter::FaceQueryFilter()
+  : m_hasFaceId(false)
+  , m_hasUriScheme(false)
+  , m_hasRemoteUri(false)
+  , m_hasLocalUri(false)
+  , m_hasFaceScope(false)
+  , m_hasFacePersistency(false)
+  , m_hasLinkType(false)
+{
+}
+
+FaceQueryFilter::FaceQueryFilter(const Block& block)
+{
+  this->wireDecode(block);
+}
+
+template<bool T>
+size_t
+FaceQueryFilter::wireEncode(EncodingImpl<T>& encoder) const
+{
+  size_t totalLength = 0;
+
+  if (m_hasLinkType) {
+    totalLength += prependNonNegativeIntegerBlock(encoder,
+                   tlv::nfd::LinkType, m_linkType);
+  }
+
+  if (m_hasFacePersistency) {
+    totalLength += prependNonNegativeIntegerBlock(encoder,
+                   tlv::nfd::FacePersistency, m_facePersistency);
+  }
+
+  if (m_hasFaceScope) {
+    totalLength += prependNonNegativeIntegerBlock(encoder,
+                   tlv::nfd::FaceScope, m_faceScope);
+  }
+
+  if (m_hasLocalUri) {
+    totalLength += prependByteArrayBlock(encoder, tlv::nfd::LocalUri,
+                   reinterpret_cast<const uint8_t*>(m_localUri.c_str()), m_localUri.size());
+  }
+
+  if (m_hasRemoteUri) {
+    totalLength += prependByteArrayBlock(encoder, tlv::nfd::Uri,
+                   reinterpret_cast<const uint8_t*>(m_remoteUri.c_str()), m_remoteUri.size());
+  }
+
+  if (m_hasUriScheme) {
+    totalLength += prependByteArrayBlock(encoder, tlv::nfd::UriScheme,
+                   reinterpret_cast<const uint8_t*>(m_uriScheme.c_str()), m_uriScheme.size());
+  }
+
+  if (m_hasFaceId) {
+    totalLength += prependNonNegativeIntegerBlock(encoder,
+                   tlv::nfd::FaceId, m_faceId);
+  }
+
+  totalLength += encoder.prependVarNumber(totalLength);
+  totalLength += encoder.prependVarNumber(tlv::nfd::FaceQueryFilter);
+  return totalLength;
+}
+
+template size_t
+FaceQueryFilter::wireEncode<true>(EncodingImpl<true>& block) const;
+
+template size_t
+FaceQueryFilter::wireEncode<false>(EncodingImpl<false>& block) const;
+
+const Block&
+FaceQueryFilter::wireEncode() const
+{
+  if (m_wire.hasWire())
+    return m_wire;
+
+  EncodingEstimator estimator;
+  size_t estimatedSize = wireEncode(estimator);
+
+  EncodingBuffer buffer(estimatedSize, 0);
+  wireEncode(buffer);
+
+  m_wire = buffer.block();
+  return m_wire;
+}
+
+void
+FaceQueryFilter::wireDecode(const Block& block)
+{
+  //all fields are optional
+  if (block.type() != tlv::nfd::FaceQueryFilter) {
+    throw Error("expecting FaceQueryFilter block");
+  }
+
+  m_wire = block;
+  m_wire.parse();
+  Block::element_const_iterator val = m_wire.elements_begin();
+
+  if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceId) {
+    m_faceId = readNonNegativeInteger(*val);
+    m_hasFaceId = true;
+    ++val;
+  }
+  else {
+    m_hasFaceId = false;
+  }
+
+  if (val != m_wire.elements_end() && val->type() == tlv::nfd::UriScheme) {
+    m_uriScheme.assign(reinterpret_cast<const char*>(val->value()), val->value_size());
+    m_hasUriScheme = true;
+    ++val;
+  }
+  else {
+    m_hasUriScheme = false;
+  }
+
+  if (val != m_wire.elements_end() && val->type() == tlv::nfd::Uri) {
+    m_remoteUri.assign(reinterpret_cast<const char*>(val->value()), val->value_size());
+    m_hasRemoteUri = true;
+    ++val;
+  }
+  else {
+    m_hasRemoteUri = false;
+  }
+
+  if (val != m_wire.elements_end() && val->type() == tlv::nfd::LocalUri) {
+    m_localUri.assign(reinterpret_cast<const char*>(val->value()), val->value_size());
+    m_hasLocalUri = true;
+    ++val;
+  }
+  else {
+    m_hasLocalUri = false;
+  }
+
+  if (val != m_wire.elements_end() && val->type() == tlv::nfd::FaceScope) {
+    m_faceScope = static_cast<FaceScope>(readNonNegativeInteger(*val));
+    m_hasFaceScope = true;
+    ++val;
+  }
+  else {
+    m_hasFaceScope = false;
+  }
+
+  if (val != m_wire.elements_end() && val->type() == tlv::nfd::FacePersistency) {
+    m_facePersistency = static_cast<FacePersistency>(readNonNegativeInteger(*val));
+    m_hasFacePersistency = true;
+    ++val;
+  }
+  else {
+    m_hasFacePersistency = false;
+  }
+
+  if (val != m_wire.elements_end() && val->type() == tlv::nfd::LinkType) {
+    m_linkType = static_cast<LinkType>(readNonNegativeInteger(*val));
+    m_hasLinkType = true;
+    ++val;
+  }
+  else {
+    m_hasLinkType = false;
+  }
+
+}
+
+FaceQueryFilter&
+FaceQueryFilter::setFaceId(uint64_t faceId)
+{
+  m_wire.reset();
+  m_faceId = faceId;
+  m_hasFaceId = true;
+  return *this;
+}
+
+FaceQueryFilter&
+FaceQueryFilter::unsetFaceId()
+{
+  m_wire.reset();
+  m_hasFaceId = false;
+  return *this;
+}
+
+FaceQueryFilter&
+FaceQueryFilter::setUriScheme(const std::string& uriScheme)
+{
+  m_wire.reset();
+  m_uriScheme = uriScheme;
+  m_hasUriScheme = true;
+  return *this;
+}
+
+FaceQueryFilter&
+FaceQueryFilter::unsetUriScheme()
+{
+  m_wire.reset();
+  m_hasUriScheme = false;
+  return *this;
+}
+
+FaceQueryFilter&
+FaceQueryFilter::setRemoteUri(const std::string& remoteUri)
+{
+  m_wire.reset();
+  m_remoteUri = remoteUri;
+  m_hasRemoteUri = true;
+  return *this;
+}
+
+FaceQueryFilter&
+FaceQueryFilter::unsetRemoteUri()
+{
+  m_wire.reset();
+  m_hasRemoteUri = false;
+  return *this;
+}
+
+FaceQueryFilter&
+FaceQueryFilter::setLocalUri(const std::string& localUri)
+{
+  m_wire.reset();
+  m_localUri = localUri;
+  m_hasLocalUri = true;
+  return *this;
+}
+
+FaceQueryFilter&
+FaceQueryFilter::unsetLocalUri()
+{
+  m_wire.reset();
+  m_hasLocalUri = false;
+  return *this;
+}
+
+FaceQueryFilter&
+FaceQueryFilter::setFaceScope(FaceScope faceScope)
+{
+  m_wire.reset();
+  m_faceScope = faceScope;
+  m_hasFaceScope = true;
+  return *this;
+}
+
+FaceQueryFilter&
+FaceQueryFilter::unsetFaceScope()
+{
+  m_wire.reset();
+  m_hasFaceScope = false;
+  return *this;
+}
+
+FaceQueryFilter&
+FaceQueryFilter::setFacePersistency(FacePersistency facePersistency)
+{
+  m_wire.reset();
+  m_facePersistency = facePersistency;
+  m_hasFacePersistency = true;
+  return *this;
+}
+
+FaceQueryFilter&
+FaceQueryFilter::unsetFacePersistency()
+{
+  m_wire.reset();
+  m_hasFacePersistency = false;
+  return *this;
+}
+
+FaceQueryFilter&
+FaceQueryFilter::setLinkType(LinkType linkType)
+{
+  m_wire.reset();
+  m_linkType = linkType;
+  m_hasLinkType = true;
+  return *this;
+}
+
+FaceQueryFilter&
+FaceQueryFilter::unsetLinkType()
+{
+  m_wire.reset();
+  m_hasLinkType = false;
+  return *this;
+}
+
+std::ostream&
+operator<<(std::ostream& os, const FaceQueryFilter& filter)
+{
+  os << "FaceQueryFilter(";
+  if (filter.hasFaceId()) {
+    os << "FaceID: " << filter.getFaceId() << ",\n";
+  }
+
+  if (filter.hasUriScheme()) {
+    os << "UriScheme: " << filter.getUriScheme() << ",\n";
+  }
+
+  if (filter.hasRemoteUri()) {
+    os << "RemoteUri: " << filter.getRemoteUri() << ",\n";
+  }
+
+  if (filter.hasLocalUri()) {
+    os << "LocalUri: " << filter.getLocalUri() << ",\n";
+  }
+
+  if (filter.hasFaceScope()) {
+    os << "FaceScope: " << filter.getFaceScope() << ",\n";
+  }
+
+  if (filter.hasFacePersistency()) {
+    os << "FacePersistency: " << filter.getFacePersistency() << ",\n";
+  }
+
+  if (filter.hasLinkType()) {
+    os << "LinkType: " << filter.getLinkType() << ",\n";
+  }
+  os << ")";
+  return os;
+}
+
+} // namespace nfd
+} // namespace ndn
+
diff --git a/src/management/nfd-face-query-filter.hpp b/src/management/nfd-face-query-filter.hpp
new file mode 100644
index 0000000..5de02fe
--- /dev/null
+++ b/src/management/nfd-face-query-filter.hpp
@@ -0,0 +1,230 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_MANAGEMENT_NFD_FACE_QUERY_FILTER_HPP
+#define NDN_MANAGEMENT_NFD_FACE_QUERY_FILTER_HPP
+
+#include "nfd-face-traits.hpp"
+
+namespace ndn {
+namespace nfd {
+
+/**
+ * \ingroup management
+ * \brief represents Face Query Filter
+ * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#Query-Operation
+ */
+class FaceQueryFilter
+{
+public:
+  class Error : public tlv::Error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : tlv::Error(what)
+    {
+    }
+  };
+
+  FaceQueryFilter();
+
+  explicit
+  FaceQueryFilter(const Block& block);
+
+  /** \brief prepend FaceQueryFilter to the encoder
+   */
+  template<bool T>
+  size_t
+  wireEncode(EncodingImpl<T>& encoder) const;
+
+  /** \brief encode FaceQueryFilter
+   */
+  const Block&
+  wireEncode() const;
+
+  /** \brief decode FaceQueryFilter
+   */
+  void
+  wireDecode(const Block& wire);
+
+public: // getters & setters
+
+  bool
+  hasFaceId() const
+  {
+    return m_hasFaceId;
+  }
+
+  uint64_t
+  getFaceId() const
+  {
+    BOOST_ASSERT(this->hasFaceId());
+    return m_faceId;
+  }
+
+  FaceQueryFilter&
+  setFaceId(uint64_t faceId);
+
+  FaceQueryFilter&
+  unsetFaceId();
+
+  bool
+  hasUriScheme() const
+  {
+    return m_hasUriScheme;
+  }
+
+  const std::string&
+  getUriScheme() const
+  {
+    BOOST_ASSERT(this->hasUriScheme());
+    return m_uriScheme;
+  }
+
+  FaceQueryFilter&
+  setUriScheme(const std::string& uriScheme);
+
+  FaceQueryFilter&
+  unsetUriScheme();
+
+  bool
+  hasRemoteUri() const
+  {
+    return m_hasRemoteUri;
+  }
+
+  const std::string&
+  getRemoteUri() const
+  {
+    BOOST_ASSERT(this->hasRemoteUri());
+    return m_remoteUri;
+  }
+
+  FaceQueryFilter&
+  setRemoteUri(const std::string& remoteUri);
+
+  FaceQueryFilter&
+  unsetRemoteUri();
+
+  bool
+  hasLocalUri() const
+  {
+    return m_hasLocalUri;
+  }
+
+  const std::string&
+  getLocalUri() const
+  {
+    BOOST_ASSERT(this->hasLocalUri());
+    return m_localUri;
+  }
+
+  FaceQueryFilter&
+  setLocalUri(const std::string& localUri);
+
+  FaceQueryFilter&
+  unsetLocalUri();
+
+  bool
+  hasFaceScope() const
+  {
+    return m_hasFaceScope;
+  }
+
+  FaceScope
+  getFaceScope() const
+  {
+    BOOST_ASSERT(this->hasFaceScope());
+    return m_faceScope;
+  }
+
+  FaceQueryFilter&
+  setFaceScope(FaceScope faceScope);
+
+  FaceQueryFilter&
+  unsetFaceScope();
+
+  bool
+  hasFacePersistency() const
+  {
+    return m_hasFacePersistency;
+  }
+
+  FacePersistency
+  getFacePersistency() const
+  {
+    BOOST_ASSERT(this->hasFacePersistency());
+    return m_facePersistency;
+  }
+
+  FaceQueryFilter&
+  setFacePersistency(FacePersistency facePersistency);
+
+  FaceQueryFilter&
+  unsetFacePersistency();
+
+  bool
+  hasLinkType() const
+  {
+    return m_hasLinkType;
+  }
+
+  LinkType
+  getLinkType() const
+  {
+    BOOST_ASSERT(this->hasLinkType());
+    return m_linkType;
+  }
+
+  FaceQueryFilter&
+  setLinkType(LinkType linkType);
+
+  FaceQueryFilter&
+  unsetLinkType();
+
+private:
+  uint64_t m_faceId;
+  std::string m_uriScheme;
+  std::string m_remoteUri;
+  std::string m_localUri;
+  FaceScope m_faceScope;
+  FacePersistency m_facePersistency;
+  LinkType m_linkType;
+
+  bool m_hasFaceId;
+  bool m_hasUriScheme;
+  bool m_hasRemoteUri;
+  bool m_hasLocalUri;
+  bool m_hasFaceScope;
+  bool m_hasFacePersistency;
+  bool m_hasLinkType;
+
+  mutable Block m_wire;
+};
+
+std::ostream&
+operator<<(std::ostream& os, const FaceQueryFilter& filter);
+
+} // namespace nfd
+} // namespace ndn
+
+#endif // NDN_MANAGEMENT_NFD_FACE_QUERY_FILTER_HPP
diff --git a/tests/unit-tests/management/test-nfd-face-query-filter.cpp b/tests/unit-tests/management/test-nfd-face-query-filter.cpp
new file mode 100644
index 0000000..575c475
--- /dev/null
+++ b/tests/unit-tests/management/test-nfd-face-query-filter.cpp
@@ -0,0 +1,97 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2014 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "management/nfd-face-query-filter.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace nfd {
+
+BOOST_AUTO_TEST_SUITE(ManagementTestNfdFaceQueryFilter)
+
+BOOST_AUTO_TEST_CASE(Encode)
+{
+  FaceQueryFilter filter1;
+  BOOST_CHECK_EQUAL(filter1.hasFaceId(), false);
+  BOOST_CHECK_EQUAL(filter1.hasUriScheme(), false);
+  BOOST_CHECK_EQUAL(filter1.hasRemoteUri(), false);
+  BOOST_CHECK_EQUAL(filter1.hasLocalUri(), false);
+  BOOST_CHECK_EQUAL(filter1.hasFaceScope(), false);
+  BOOST_CHECK_EQUAL(filter1.hasFacePersistency(), false);
+  BOOST_CHECK_EQUAL(filter1.hasLinkType(), false);
+
+  filter1.setFaceId(100)
+         .setUriScheme("tcp4")
+         .setRemoteUri("tcp4://192.0.2.1:6363")
+         .setLocalUri("tcp4://192.0.2.2:55555")
+         .setFaceScope(FACE_SCOPE_LOCAL)
+         .setFacePersistency(FACE_PERSISTENCY_ON_DEMAND)
+         .setLinkType(LINK_TYPE_MULTI_ACCESS);
+
+  Block wire;
+  BOOST_REQUIRE_NO_THROW(wire = filter1.wireEncode());
+
+  // These octets are obtained by the snippet below.
+  // This check is intended to detect unexpected encoding change in the future.
+  // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) {
+  //  printf("0x%02x, ", *it);
+  // }
+  static const uint8_t expected[] = {
+    0x96, 0x41, 0x69, 0x01, 0x64, 0x83, 0x04, 0x74, 0x63, 0x70,
+    0x34, 0x72, 0x15, 0x74, 0x63, 0x70, 0x34, 0x3a, 0x2f, 0x2f,
+    0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32, 0x2e, 0x31, 0x3a,
+    0x36, 0x33, 0x36, 0x33, 0x81, 0x16, 0x74, 0x63, 0x70, 0x34,
+    0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x30, 0x2e, 0x32,
+    0x2e, 0x32, 0x3a, 0x35, 0x35, 0x35, 0x35, 0x35, 0x84, 0x01,
+    0x01, 0x85, 0x01, 0x01, 0x86, 0x01, 0x01,
+  };
+
+  BOOST_CHECK_EQUAL_COLLECTIONS(expected, expected + sizeof(expected),
+                                wire.begin(), wire.end());
+
+  BOOST_REQUIRE_NO_THROW(FaceQueryFilter(wire));
+
+  FaceQueryFilter filter2(wire);
+  BOOST_CHECK_EQUAL(filter1.getFaceId(), filter2.getFaceId());
+  BOOST_CHECK_EQUAL(filter1.getUriScheme(), filter2.getUriScheme());
+  BOOST_CHECK_EQUAL(filter1.getRemoteUri(), filter2.getRemoteUri());
+  BOOST_CHECK_EQUAL(filter1.getLocalUri(), filter2.getLocalUri());
+  BOOST_CHECK_EQUAL(filter1.getFaceScope(), filter2.getFaceScope());
+  BOOST_CHECK_EQUAL(filter1.getFacePersistency(), filter2.getFacePersistency());
+  BOOST_CHECK_EQUAL(filter1.getLinkType(), filter2.getLinkType());
+
+  std::ostringstream os;
+  os << filter2;
+  BOOST_CHECK_EQUAL(os.str(), "FaceQueryFilter(FaceID: 100,\n"
+                              "UriScheme: tcp4,\n"
+                              "RemoteUri: tcp4://192.0.2.1:6363,\n"
+                              "LocalUri: tcp4://192.0.2.2:55555,\n"
+                              "FaceScope: local,\n"
+                              "FacePersistency: on-demand,\n"
+                              "LinkType: multi-access,\n"
+                              ")");
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace nfd
+} // namespace ndn