From 72ffd44a10c128f6a7c7cae7f3b7f6ad4be3aa5c Mon Sep 17 00:00:00 2001
From: Barry Xu <Barry.Xu@sony.com>
Date: Tue, 7 Jan 2020 09:43:07 +0800
Subject: [PATCH 01/13] get publisher and subscription information from topic
 name

Signed-off-by: Barry Xu <Barry.Xu@sony.com>
---
 rclcpp/CMakeLists.txt                         |   1 +
 rclcpp/include/rclcpp/node.hpp                |  48 ++++++++
 .../rclcpp/node_interfaces/node_graph.hpp     |  27 +++++
 .../node_interfaces/node_graph_interface.hpp  |  34 ++++++
 rclcpp/src/rclcpp/node.cpp                    |  12 ++
 .../src/rclcpp/node_interfaces/node_graph.cpp | 100 +++++++++++++++
 rclcpp/test/test_node.cpp                     | 114 ++++++++++++++++++
 7 files changed, 336 insertions(+)

diff --git a/rclcpp/CMakeLists.txt b/rclcpp/CMakeLists.txt
index 42f9eb3f81..dc8f5d6bf9 100644
--- a/rclcpp/CMakeLists.txt
+++ b/rclcpp/CMakeLists.txt
@@ -247,6 +247,7 @@ if(BUILD_TESTING)
       "rmw"
       "rosidl_generator_cpp"
       "rosidl_typesupport_cpp"
+      "test_msgs"
     )
     target_link_libraries(test_node ${PROJECT_NAME})
   endif()
diff --git a/rclcpp/include/rclcpp/node.hpp b/rclcpp/include/rclcpp/node.hpp
index 4b6bcfbc91..f396fb8df2 100644
--- a/rclcpp/include/rclcpp/node.hpp
+++ b/rclcpp/include/rclcpp/node.hpp
@@ -1072,6 +1072,54 @@ class Node : public std::enable_shared_from_this<Node>
   bool
   assert_liveliness() const;
 
+  /// Return a list of publishers about topic information to a given topic.
+  /**
+   * The returned parameter is a list of topic info, where each topic info will
+   * contain the node name, node namespace, topic type, participant's GID and its QoS profile.
+   *
+   * "topic_name" may be a relative, private or fully qualified topic name.
+   * A relative or private topic will be expanded using this node's namespace and name, if
+   * the "no_mangle" param is set to false.
+   *
+   * The queried topic name is not remapped.
+   *
+   * "no_mangle" defaults to false.
+   *
+   * \param[in] topic_name the topic_name on which to find the publishers.
+   * \param[in] no_mangle if false, the given topic name will be expanded
+   *    to its fully qualified name.
+   * \return a list of TopicInfo representing all the publishers on this topic.
+   * \throws InvalidTopicNameError if the given topic_name is invalid.
+   * \throws std::runtime_error if internal error happens.
+   */
+  RCLCPP_PUBLIC
+  std::vector<rclcpp::TopicInfo>
+  get_publishers_info_by_topic(const std::string & topic_name, bool no_mangle = false) const;
+
+  /// Return a list of subscriptions about topic information to a given topic.
+  /**
+   * The returned parameter is a list of topic info, where each topic info will
+   * contain the node name, node namespace, topic type, participant's GID and its QoS profile.
+   *
+   * "topic_name" may be a relative, private or fully qualified topic name.
+   * A relative or private topic will be expanded using this node's namespace and name, if
+   * the "no_mangle" param is set to false.
+   *
+   * The queried topic name is not remapped.
+   *
+   * "no_mangle" defaults to false.
+   *
+   * \param[in] topic_name the topic_name on which to find the subscriptions.
+   * \param[in] no_mangle if false, the given topic name will be expanded
+   *    to its fully qualified name.
+   * \return a list of TopicInfo representing all the subscriptions on this topic.
+   * \throws InvalidTopicNameError if the given topic_name is invalid.
+   * \throws std::runtime_error if internal error happens.
+   */
+  RCLCPP_PUBLIC
+  std::vector<rclcpp::TopicInfo>
+  get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle = false) const;
+
 protected:
   /// Construct a sub-node, which will extend the namespace of all entities created with it.
   /**
diff --git a/rclcpp/include/rclcpp/node_interfaces/node_graph.hpp b/rclcpp/include/rclcpp/node_interfaces/node_graph.hpp
index ff2d91b261..74ff364463 100644
--- a/rclcpp/include/rclcpp/node_interfaces/node_graph.hpp
+++ b/rclcpp/include/rclcpp/node_interfaces/node_graph.hpp
@@ -30,6 +30,7 @@
 #include "rclcpp/node_interfaces/node_base_interface.hpp"
 #include "rclcpp/node_interfaces/node_graph_interface.hpp"
 #include "rclcpp/visibility_control.hpp"
+#include "rmw/topic_info_array.h"
 
 namespace rclcpp
 {
@@ -117,9 +118,35 @@ class NodeGraph : public NodeGraphInterface
   size_t
   count_graph_users() override;
 
+  RCLCPP_PUBLIC
+  std::vector<rclcpp::TopicInfo>
+  get_publishers_info_by_topic(
+    const std::string & topic_name,
+    bool no_mangle = false) const override;
+
+  RCLCPP_PUBLIC
+  std::vector<rclcpp::TopicInfo>
+  get_subscriptions_info_by_topic(
+    const std::string & topic_name,
+    bool no_mangle = false) const override;
+
 private:
   RCLCPP_DISABLE_COPY(NodeGraph)
 
+  typedef rcl_ret_t (* rcl_get_info_by_topic_func_t)(
+    const rcl_node_t * node,
+    rcutils_allocator_t * allocator,
+    const char * topic_name,
+    bool no_mangle,
+    rmw_topic_info_array_t * info_array);
+
+  std::vector<rclcpp::TopicInfo>
+  get_info_by_topic(
+    const std::string & topic_name,
+    bool no_mangle,
+    const std::string & type,
+    rcl_get_info_by_topic_func_t rcl_get_info_by_topic) const;
+
   /// Handle to the NodeBaseInterface given in the constructor.
   rclcpp::node_interfaces::NodeBaseInterface * node_base_;
 
diff --git a/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp b/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
index 022984dd47..b4e14007f6 100644
--- a/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
+++ b/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
@@ -29,6 +29,20 @@
 
 namespace rclcpp
 {
+
+/**
+ * Use to get topic information that containing the node name, node namespace, topic type,
+ * participant's GID and its QoS profile
+ */
+struct RCLCPP_PUBLIC TopicInfo
+{
+  std::string node_name;
+  std::string node_namespace;
+  std::string topic_type;
+  uint8_t gid[RMW_GID_STORAGE_SIZE];
+  rmw_qos_profile_t qos_profile;
+};
+
 namespace node_interfaces
 {
 
@@ -150,6 +164,26 @@ class NodeGraphInterface
   virtual
   size_t
   count_graph_users() = 0;
+
+  /// Returns a list of all publishers to a topic.
+  /**
+   * Each element in the list will contain the node name, node namespace, topic type,
+   * gid and the qos profile of the publisher.
+   */
+  RCLCPP_PUBLIC
+  virtual
+  std::vector<rclcpp::TopicInfo>
+  get_publishers_info_by_topic(const std::string & topic_name, bool no_mangle = false) const = 0;
+
+  /// Returns a list of all subscriptions to a topic.
+  /**
+   * Each element in the list will contain the node name, node namespace, topic type,
+   * gid and the qos profile of the subscription.
+   */
+  RCLCPP_PUBLIC
+  virtual
+  std::vector<rclcpp::TopicInfo>
+  get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle = false) const = 0;
 };
 
 }  // namespace node_interfaces
diff --git a/rclcpp/src/rclcpp/node.cpp b/rclcpp/src/rclcpp/node.cpp
index 3cc13b0947..f127a36f46 100644
--- a/rclcpp/src/rclcpp/node.cpp
+++ b/rclcpp/src/rclcpp/node.cpp
@@ -493,3 +493,15 @@ Node::assert_liveliness() const
 {
   return node_base_->assert_liveliness();
 }
+
+std::vector<rclcpp::TopicInfo>
+Node::get_publishers_info_by_topic(const std::string & topic_name, bool no_mangle) const
+{
+  return node_graph_->get_publishers_info_by_topic(topic_name, no_mangle);
+}
+
+std::vector<rclcpp::TopicInfo>
+Node::get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle) const
+{
+  return node_graph_->get_subscriptions_info_by_topic(topic_name, no_mangle);
+}
diff --git a/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp b/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
index 11347881b3..a0ddd747b4 100644
--- a/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
+++ b/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
@@ -369,3 +369,103 @@ NodeGraph::count_graph_users()
 {
   return graph_users_count_.load();
 }
+
+static
+rclcpp::TopicInfo
+convert_to_topic_info(const rmw_topic_info_t * info)
+{
+  rclcpp::TopicInfo topic_info;
+  topic_info.node_name = info->node_name;
+  topic_info.node_namespace = info->node_namespace;
+  topic_info.topic_type = info->topic_type;
+  memcpy(topic_info.gid, info->gid, RMW_GID_STORAGE_SIZE);
+  memcpy(&topic_info.qos_profile, &info->qos_profile, sizeof(rmw_qos_profile_t));
+  return topic_info;
+}
+
+static
+std::vector<rclcpp::TopicInfo>
+convert_to_topic_info_list(const rmw_topic_info_array_t * info_array)
+{
+  std::vector<rclcpp::TopicInfo> topic_info_list;
+  for (size_t i = 0; i < info_array->count; ++i) {
+    rmw_topic_info_t topic_info = info_array->info_array[i];
+    auto topic_info_item = convert_to_topic_info(&topic_info);
+    topic_info_list.push_back(topic_info_item);
+  }
+  return topic_info_list;
+}
+
+std::vector<rclcpp::TopicInfo>
+NodeGraph::get_info_by_topic(
+  const std::string & topic_name,
+  bool no_mangle,
+  const std::string & type,
+  rcl_get_info_by_topic_func_t rcl_get_info_by_topic) const
+{
+  std::vector<rclcpp::TopicInfo> topic_info_list;
+
+  auto rcl_node_handle = node_base_->get_rcl_node_handle();
+  auto fqdn = rclcpp::expand_topic_or_service_name(
+    topic_name,
+    rcl_node_get_name(rcl_node_handle),
+    rcl_node_get_namespace(rcl_node_handle),
+    false);    // false = not a service
+
+  rcutils_allocator_t allocator = rcutils_get_default_allocator();
+  rmw_topic_info_array_t info_array = rmw_get_zero_initialized_topic_info_array();
+  auto ret =
+    rcl_get_info_by_topic(rcl_node_handle, &allocator, fqdn.c_str(), no_mangle, &info_array);
+  if (ret != RCL_RET_OK) {
+    // *INDENT-OFF*
+    auto error_msg =
+      std::string("Failed to get information by topic for: ") + type + std::string(":");
+    if (ret == RCL_RET_UNSUPPORTED) {
+      error_msg += std::string("function not supported by RMW_IMPLEMENTATION");
+    } else {
+      error_msg += rcl_get_error_string().str;
+    }
+    rcl_reset_error();
+    if (rmw_topic_info_array_fini(&info_array, &allocator) != RMW_RET_OK) {
+      error_msg += std::string(", failed also to cleanup topic info array, leaking memory: ")
+        + rcl_get_error_string().str;
+      rcl_reset_error();
+    }
+    throw std::runtime_error(error_msg);
+    // *INDENT-ON*
+  }
+
+  topic_info_list = convert_to_topic_info_list(&info_array);
+  if (rmw_topic_info_array_fini(&info_array, &allocator) != RMW_RET_OK) {
+    // *INDENT-OFF*
+    throw std::runtime_error(
+      std::string("rmw_topic_info_array_fini failed."));
+    // *INDENT-ON*
+  }
+
+  return topic_info_list;
+}
+
+std::vector<rclcpp::TopicInfo>
+NodeGraph::get_publishers_info_by_topic(
+  const std::string & topic_name,
+  bool no_mangle) const
+{
+  return get_info_by_topic(
+    topic_name,
+    no_mangle,
+    "publishers",
+    rcl_get_publishers_info_by_topic);
+}
+
+std::vector<rclcpp::TopicInfo>
+NodeGraph::get_subscriptions_info_by_topic(
+  const std::string & topic_name,
+  bool no_mangle) const
+{
+  return get_info_by_topic(
+    topic_name,
+    no_mangle,
+    "subscriptions",
+    rcl_get_subscriptions_info_by_topic);
+}
diff --git a/rclcpp/test/test_node.cpp b/rclcpp/test/test_node.cpp
index 2bab00e678..b8dd3bb9a9 100644
--- a/rclcpp/test/test_node.cpp
+++ b/rclcpp/test/test_node.cpp
@@ -26,6 +26,7 @@
 #include "rclcpp/rclcpp.hpp"
 
 #include "rcpputils/filesystem_helper.hpp"
+#include "test_msgs/msg/basic_types.hpp"
 
 class TestNode : public ::testing::Test
 {
@@ -2510,3 +2511,116 @@ TEST_F(TestNode, set_on_parameters_set_callback_set_on_parameters_set_callback)
     node->set_parameter(rclcpp::Parameter("intparam", 40));
   }, rclcpp::exceptions::ParameterModifiedInCallbackException);
 }
+
+// test that calling get_publishers_info_by_topic and get_subscriptions_info_by_topic
+TEST_F(TestNode, get_publishers_subscriptions_info_by_topic) {
+  auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
+  std::string topic_name = "test_topic_info";
+  std::string fq_topic_name = rclcpp::expand_topic_or_service_name(
+    topic_name, node->get_name(), node->get_namespace());
+
+  // Lists should be empty
+  EXPECT_TRUE(node->get_publishers_info_by_topic(fq_topic_name).empty());
+  EXPECT_TRUE(node->get_subscriptions_info_by_topic(fq_topic_name).empty());
+
+  // Add a publisher
+  rclcpp::QoSInitialization qos_initialization =
+  {
+    RMW_QOS_POLICY_HISTORY_KEEP_ALL,
+    10
+  };
+  rmw_qos_profile_t rmw_qos_profile_default =
+  {
+    RMW_QOS_POLICY_HISTORY_KEEP_ALL,
+    10,
+    RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT,
+    RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL,
+    {1, 12345},
+    {20, 9887665},
+    RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC,
+    {5, 23456},
+    false
+  };
+  rclcpp::QoS qos = rclcpp::QoS(qos_initialization, rmw_qos_profile_default);
+  auto publisher = node->create_publisher<test_msgs::msg::BasicTypes>(topic_name, qos);
+  // List should have one item
+  auto publisher_list = node->get_publishers_info_by_topic(fq_topic_name);
+  EXPECT_EQ(publisher_list.size(), (size_t)1);
+  // Subscription list should be empty
+  EXPECT_TRUE(node->get_subscriptions_info_by_topic(fq_topic_name).empty());
+  // Verify publisher list has the right data.
+  EXPECT_EQ(node->get_name(), publisher_list[0].node_name);
+  EXPECT_EQ(node->get_namespace(), publisher_list[0].node_namespace);
+  EXPECT_EQ("test_msgs::msg::dds_::BasicTypes_", publisher_list[0].topic_type);
+  auto actual_qos_profile = publisher_list[0].qos_profile;
+
+  auto assert_qos_profile = [](const rmw_qos_profile_t & qos1, const rmw_qos_profile_t & qos2) {
+      // Depth and history are skipped because they are not retrieved.
+      EXPECT_EQ(qos1.reliability, qos2.reliability);
+      EXPECT_EQ(qos1.durability, qos2.durability);
+      EXPECT_EQ(memcmp(&qos1.deadline, &qos2.deadline, sizeof(struct rmw_time_t)), 0);
+      EXPECT_EQ(memcmp(&qos1.lifespan, &qos2.lifespan, sizeof(struct rmw_time_t)), 0);
+      EXPECT_EQ(qos1.liveliness, qos2.liveliness);
+      EXPECT_EQ(
+        memcmp(
+          &qos1.liveliness_lease_duration,
+          &qos2.liveliness_lease_duration,
+          sizeof(struct rmw_time_t)),
+        0);
+    };
+
+  assert_qos_profile(qos.get_rmw_qos_profile(), actual_qos_profile);
+
+  // Add a subscription
+  rclcpp::QoSInitialization qos_initialization2 =
+  {
+    RMW_QOS_POLICY_HISTORY_KEEP_LAST,
+    0
+  };
+  rmw_qos_profile_t rmw_qos_profile_default2 =
+  {
+    RMW_QOS_POLICY_HISTORY_KEEP_LAST,
+    0,
+    RMW_QOS_POLICY_RELIABILITY_RELIABLE,
+    RMW_QOS_POLICY_DURABILITY_VOLATILE,
+    {15, 1678},
+    {29, 2345},
+    RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_NODE,
+    {5, 23456},
+    false
+  };
+  rclcpp::QoS qos2 = rclcpp::QoS(qos_initialization2, rmw_qos_profile_default2);
+  auto callback = [](const test_msgs::msg::BasicTypes::SharedPtr msg) {
+      (void)msg;
+    };
+  auto subscriber =
+    node->create_subscription<test_msgs::msg::BasicTypes>(topic_name, qos2, callback);
+
+  // Both lists should have one item
+  publisher_list = node->get_publishers_info_by_topic(fq_topic_name);
+  auto subscription_list = node->get_subscriptions_info_by_topic(fq_topic_name);
+  EXPECT_EQ(publisher_list.size(), (size_t)1);
+  EXPECT_EQ(subscription_list.size(), (size_t)1);
+
+  // Verify publisher and subscription list has the right data.
+  EXPECT_EQ(node->get_name(), publisher_list[0].node_name);
+  EXPECT_EQ(node->get_namespace(), publisher_list[0].node_namespace);
+  EXPECT_EQ("test_msgs::msg::dds_::BasicTypes_", publisher_list[0].topic_type);
+  auto publisher_qos_profile = publisher_list[0].qos_profile;
+  assert_qos_profile(qos.get_rmw_qos_profile(), publisher_qos_profile);
+  EXPECT_EQ(node->get_name(), subscription_list[0].node_name);
+  EXPECT_EQ(node->get_namespace(), subscription_list[0].node_namespace);
+  EXPECT_EQ("test_msgs::msg::dds_::BasicTypes_", subscription_list[0].topic_type);
+  auto subscription_qos_profile = subscription_list[0].qos_profile;
+  assert_qos_profile(qos2.get_rmw_qos_profile(), subscription_qos_profile);
+
+  // Error cases
+  EXPECT_THROW(
+  {
+    publisher_list = node->get_publishers_info_by_topic("13");
+  }, rclcpp::exceptions::InvalidTopicNameError);
+  EXPECT_THROW(
+  {
+    subscription_list = node->get_subscriptions_info_by_topic("13");
+  }, rclcpp::exceptions::InvalidTopicNameError);
+}

From b2e1d030163f5f10b73aa792181c9553bbf49c07 Mon Sep 17 00:00:00 2001
From: Barry Xu <Barry.Xu@sony.com>
Date: Wed, 15 Jan 2020 14:51:52 +0800
Subject: [PATCH 02/13] Update with comments and fix some changes of rmw

Signed-off-by: Barry Xu <Barry.Xu@sony.com>
---
 rclcpp/include/rclcpp/node.hpp                | 26 +++----
 .../rclcpp/node_interfaces/node_graph.hpp     | 20 +----
 .../node_interfaces/node_graph_interface.hpp  | 41 ++++++----
 rclcpp/src/rclcpp/node.cpp                    |  4 +-
 .../src/rclcpp/node_interfaces/node_graph.cpp | 75 ++++++++-----------
 rclcpp/test/test_node.cpp                     | 15 ++--
 6 files changed, 87 insertions(+), 94 deletions(-)

diff --git a/rclcpp/include/rclcpp/node.hpp b/rclcpp/include/rclcpp/node.hpp
index f396fb8df2..cdd44dfce2 100644
--- a/rclcpp/include/rclcpp/node.hpp
+++ b/rclcpp/include/rclcpp/node.hpp
@@ -1072,10 +1072,11 @@ class Node : public std::enable_shared_from_this<Node>
   bool
   assert_liveliness() const;
 
-  /// Return a list of publishers about topic information to a given topic.
+  /// Return a list of publishers about topic endpoint information to a given topic.
   /**
-   * The returned parameter is a list of topic info, where each topic info will
-   * contain the node name, node namespace, topic type, participant's GID and its QoS profile.
+   * The returned parameter is a list of topic endpoint information, where each item will contain
+   * the node name, node namespace, topic type, endpoint type, participant's GID and its QoS
+   * profile.
    *
    * "topic_name" may be a relative, private or fully qualified topic name.
    * A relative or private topic will be expanded using this node's namespace and name, if
@@ -1083,23 +1084,22 @@ class Node : public std::enable_shared_from_this<Node>
    *
    * The queried topic name is not remapped.
    *
-   * "no_mangle" defaults to false.
-   *
    * \param[in] topic_name the topic_name on which to find the publishers.
    * \param[in] no_mangle if false, the given topic name will be expanded
-   *    to its fully qualified name.
+   *    to its fully qualified name. Default to `false`.
    * \return a list of TopicInfo representing all the publishers on this topic.
    * \throws InvalidTopicNameError if the given topic_name is invalid.
    * \throws std::runtime_error if internal error happens.
    */
   RCLCPP_PUBLIC
-  std::vector<rclcpp::TopicInfo>
+  std::vector<rclcpp::TopicEndpointInfo>
   get_publishers_info_by_topic(const std::string & topic_name, bool no_mangle = false) const;
 
-  /// Return a list of subscriptions about topic information to a given topic.
+  /// Return a list of subscriptions about topic endpoint information to a given topic.
   /**
-   * The returned parameter is a list of topic info, where each topic info will
-   * contain the node name, node namespace, topic type, participant's GID and its QoS profile.
+   * The returned parameter is a list of topic endpoint information, where each item will contain
+   * the node name, node namespace, topic type, endpoint type, participant's GID and its QoS
+   * profile.
    *
    * "topic_name" may be a relative, private or fully qualified topic name.
    * A relative or private topic will be expanded using this node's namespace and name, if
@@ -1107,17 +1107,15 @@ class Node : public std::enable_shared_from_this<Node>
    *
    * The queried topic name is not remapped.
    *
-   * "no_mangle" defaults to false.
-   *
    * \param[in] topic_name the topic_name on which to find the subscriptions.
    * \param[in] no_mangle if false, the given topic name will be expanded
-   *    to its fully qualified name.
+   *    to its fully qualified name. Default to `false`.
    * \return a list of TopicInfo representing all the subscriptions on this topic.
    * \throws InvalidTopicNameError if the given topic_name is invalid.
    * \throws std::runtime_error if internal error happens.
    */
   RCLCPP_PUBLIC
-  std::vector<rclcpp::TopicInfo>
+  std::vector<rclcpp::TopicEndpointInfo>
   get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle = false) const;
 
 protected:
diff --git a/rclcpp/include/rclcpp/node_interfaces/node_graph.hpp b/rclcpp/include/rclcpp/node_interfaces/node_graph.hpp
index 74ff364463..26d91aecfd 100644
--- a/rclcpp/include/rclcpp/node_interfaces/node_graph.hpp
+++ b/rclcpp/include/rclcpp/node_interfaces/node_graph.hpp
@@ -30,7 +30,7 @@
 #include "rclcpp/node_interfaces/node_base_interface.hpp"
 #include "rclcpp/node_interfaces/node_graph_interface.hpp"
 #include "rclcpp/visibility_control.hpp"
-#include "rmw/topic_info_array.h"
+#include "rmw/topic_endpoint_info_array.h"
 
 namespace rclcpp
 {
@@ -119,13 +119,13 @@ class NodeGraph : public NodeGraphInterface
   count_graph_users() override;
 
   RCLCPP_PUBLIC
-  std::vector<rclcpp::TopicInfo>
+  std::vector<rclcpp::TopicEndpointInfo>
   get_publishers_info_by_topic(
     const std::string & topic_name,
     bool no_mangle = false) const override;
 
   RCLCPP_PUBLIC
-  std::vector<rclcpp::TopicInfo>
+  std::vector<rclcpp::TopicEndpointInfo>
   get_subscriptions_info_by_topic(
     const std::string & topic_name,
     bool no_mangle = false) const override;
@@ -133,20 +133,6 @@ class NodeGraph : public NodeGraphInterface
 private:
   RCLCPP_DISABLE_COPY(NodeGraph)
 
-  typedef rcl_ret_t (* rcl_get_info_by_topic_func_t)(
-    const rcl_node_t * node,
-    rcutils_allocator_t * allocator,
-    const char * topic_name,
-    bool no_mangle,
-    rmw_topic_info_array_t * info_array);
-
-  std::vector<rclcpp::TopicInfo>
-  get_info_by_topic(
-    const std::string & topic_name,
-    bool no_mangle,
-    const std::string & type,
-    rcl_get_info_by_topic_func_t rcl_get_info_by_topic) const;
-
   /// Handle to the NodeBaseInterface given in the constructor.
   rclcpp::node_interfaces::NodeBaseInterface * node_base_;
 
diff --git a/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp b/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
index b4e14007f6..1cd6cf8325 100644
--- a/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
+++ b/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
@@ -15,6 +15,7 @@
 #ifndef RCLCPP__NODE_INTERFACES__NODE_GRAPH_INTERFACE_HPP_
 #define RCLCPP__NODE_INTERFACES__NODE_GRAPH_INTERFACE_HPP_
 
+#include <array>
 #include <chrono>
 #include <map>
 #include <string>
@@ -25,22 +26,38 @@
 
 #include "rclcpp/event.hpp"
 #include "rclcpp/macros.hpp"
+#include "rclcpp/qos.hpp"
 #include "rclcpp/visibility_control.hpp"
+#include "rmw/topic_endpoint_info.h"
 
 namespace rclcpp
 {
 
+using EndpointType = rmw_endpoint_type_t;
+
 /**
- * Use to get topic information that containing the node name, node namespace, topic type,
- * participant's GID and its QoS profile
+ * Use to get topic endpoint information that containing the node name, node namespace, topic type,
+ * endpoint type, GID of endpoint and its QoS.
  */
-struct RCLCPP_PUBLIC TopicInfo
+struct RCLCPP_PUBLIC TopicEndpointInfo
 {
   std::string node_name;
   std::string node_namespace;
   std::string topic_type;
-  uint8_t gid[RMW_GID_STORAGE_SIZE];
-  rmw_qos_profile_t qos_profile;
+  rclcpp::EndpointType endpoint_type;
+  std::array<uint8_t, RMW_GID_STORAGE_SIZE> endpoint_gid;
+  rclcpp::QoS qos;
+
+  /// Constructor which convert rmw_topic_endpoint_info_t to TopicEndpointInfo.
+  TopicEndpointInfo(const rmw_topic_endpoint_info_t & info)
+  : node_name(info.node_name),
+    node_namespace(info.node_namespace),
+    topic_type(info.topic_type),
+    endpoint_type(info.endpoint_type),
+    qos({info.qos_profile.history, info.qos_profile.depth}, info.qos_profile)
+  {
+    std::copy(info.endpoint_gid, info.endpoint_gid+RMW_GID_STORAGE_SIZE, endpoint_gid.begin());
+  }
 };
 
 namespace node_interfaces
@@ -165,24 +182,22 @@ class NodeGraphInterface
   size_t
   count_graph_users() = 0;
 
-  /// Returns a list of all publishers to a topic.
+  /// Return a list of publishers about topic endpoint information to a given topic.
   /**
-   * Each element in the list will contain the node name, node namespace, topic type,
-   * gid and the qos profile of the publisher.
+   * \sa rclcpp::Node::get_publishers_info_by_topic
    */
   RCLCPP_PUBLIC
   virtual
-  std::vector<rclcpp::TopicInfo>
+  std::vector<rclcpp::TopicEndpointInfo>
   get_publishers_info_by_topic(const std::string & topic_name, bool no_mangle = false) const = 0;
 
-  /// Returns a list of all subscriptions to a topic.
+  /// Return a list of subscriptions about topic endpoint information to a given topic.
   /**
-   * Each element in the list will contain the node name, node namespace, topic type,
-   * gid and the qos profile of the subscription.
+   * \sa rclcpp::Node::get_subscriptions_info_by_topic
    */
   RCLCPP_PUBLIC
   virtual
-  std::vector<rclcpp::TopicInfo>
+  std::vector<rclcpp::TopicEndpointInfo>
   get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle = false) const = 0;
 };
 
diff --git a/rclcpp/src/rclcpp/node.cpp b/rclcpp/src/rclcpp/node.cpp
index f127a36f46..0d65f2b686 100644
--- a/rclcpp/src/rclcpp/node.cpp
+++ b/rclcpp/src/rclcpp/node.cpp
@@ -494,13 +494,13 @@ Node::assert_liveliness() const
   return node_base_->assert_liveliness();
 }
 
-std::vector<rclcpp::TopicInfo>
+std::vector<rclcpp::TopicEndpointInfo>
 Node::get_publishers_info_by_topic(const std::string & topic_name, bool no_mangle) const
 {
   return node_graph_->get_publishers_info_by_topic(topic_name, no_mangle);
 }
 
-std::vector<rclcpp::TopicInfo>
+std::vector<rclcpp::TopicEndpointInfo>
 Node::get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle) const
 {
   return node_graph_->get_subscriptions_info_by_topic(topic_name, no_mangle);
diff --git a/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp b/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
index a0ddd747b4..758f22333a 100644
--- a/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
+++ b/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
@@ -28,6 +28,12 @@
 using rclcpp::node_interfaces::NodeGraph;
 using rclcpp::exceptions::throw_from_rcl_error;
 using rclcpp::graph_listener::GraphListener;
+using rcl_get_info_by_topic_func_t = rcl_ret_t (* )(
+  const rcl_node_t *,
+  rcutils_allocator_t *,
+  const char *,
+  bool,
+  rmw_topic_endpoint_info_array_t *);
 
 NodeGraph::NodeGraph(rclcpp::node_interfaces::NodeBaseInterface * node_base)
 : node_base_(node_base),
@@ -371,41 +377,28 @@ NodeGraph::count_graph_users()
 }
 
 static
-rclcpp::TopicInfo
-convert_to_topic_info(const rmw_topic_info_t * info)
+std::vector<rclcpp::TopicEndpointInfo>
+convert_to_topic_info_list(const rmw_topic_endpoint_info_array_t & info_array)
 {
-  rclcpp::TopicInfo topic_info;
-  topic_info.node_name = info->node_name;
-  topic_info.node_namespace = info->node_namespace;
-  topic_info.topic_type = info->topic_type;
-  memcpy(topic_info.gid, info->gid, RMW_GID_STORAGE_SIZE);
-  memcpy(&topic_info.qos_profile, &info->qos_profile, sizeof(rmw_qos_profile_t));
-  return topic_info;
-}
-
-static
-std::vector<rclcpp::TopicInfo>
-convert_to_topic_info_list(const rmw_topic_info_array_t * info_array)
-{
-  std::vector<rclcpp::TopicInfo> topic_info_list;
-  for (size_t i = 0; i < info_array->count; ++i) {
-    rmw_topic_info_t topic_info = info_array->info_array[i];
-    auto topic_info_item = convert_to_topic_info(&topic_info);
-    topic_info_list.push_back(topic_info_item);
+  std::vector<rclcpp::TopicEndpointInfo> topic_info_list;
+  for (size_t i = 0; i < info_array.count; ++i) {
+    topic_info_list.push_back(rclcpp::TopicEndpointInfo(info_array.info_array[i]));
   }
   return topic_info_list;
 }
 
-std::vector<rclcpp::TopicInfo>
-NodeGraph::get_info_by_topic(
+template <typename TypeT, typename FunctionT>
+static std::vector<rclcpp::TopicEndpointInfo>
+get_info_by_topic(
+  rclcpp::node_interfaces::NodeBaseInterface * node_base,
   const std::string & topic_name,
   bool no_mangle,
-  const std::string & type,
-  rcl_get_info_by_topic_func_t rcl_get_info_by_topic) const
+  TypeT type,
+  FunctionT rcl_get_info_by_topic)
 {
-  std::vector<rclcpp::TopicInfo> topic_info_list;
+  std::vector<rclcpp::TopicEndpointInfo> topic_info_list;
 
-  auto rcl_node_handle = node_base_->get_rcl_node_handle();
+  auto rcl_node_handle = node_base->get_rcl_node_handle();
   auto fqdn = rclcpp::expand_topic_or_service_name(
     topic_name,
     rcl_node_get_name(rcl_node_handle),
@@ -413,11 +406,10 @@ NodeGraph::get_info_by_topic(
     false);    // false = not a service
 
   rcutils_allocator_t allocator = rcutils_get_default_allocator();
-  rmw_topic_info_array_t info_array = rmw_get_zero_initialized_topic_info_array();
+  rmw_topic_endpoint_info_array_t info_array = rmw_get_zero_initialized_topic_endpoint_info_array();
   auto ret =
     rcl_get_info_by_topic(rcl_node_handle, &allocator, fqdn.c_str(), no_mangle, &info_array);
   if (ret != RCL_RET_OK) {
-    // *INDENT-OFF*
     auto error_msg =
       std::string("Failed to get information by topic for: ") + type + std::string(":");
     if (ret == RCL_RET_UNSUPPORTED) {
@@ -426,44 +418,43 @@ NodeGraph::get_info_by_topic(
       error_msg += rcl_get_error_string().str;
     }
     rcl_reset_error();
-    if (rmw_topic_info_array_fini(&info_array, &allocator) != RMW_RET_OK) {
+    if (rmw_topic_endpoint_info_array_fini(&info_array, &allocator) != RMW_RET_OK) {
       error_msg += std::string(", failed also to cleanup topic info array, leaking memory: ")
         + rcl_get_error_string().str;
       rcl_reset_error();
     }
-    throw std::runtime_error(error_msg);
-    // *INDENT-ON*
+    throw_from_rcl_error(ret, error_msg);
   }
 
-  topic_info_list = convert_to_topic_info_list(&info_array);
-  if (rmw_topic_info_array_fini(&info_array, &allocator) != RMW_RET_OK) {
-    // *INDENT-OFF*
-    throw std::runtime_error(
-      std::string("rmw_topic_info_array_fini failed."));
-    // *INDENT-ON*
+  topic_info_list = convert_to_topic_info_list(info_array);
+  ret = rmw_topic_endpoint_info_array_fini(&info_array, &allocator);
+  if (ret != RMW_RET_OK) {
+    throw_from_rcl_error(ret, "rmw_topic_info_array_fini failed.");
   }
 
   return topic_info_list;
 }
 
-std::vector<rclcpp::TopicInfo>
+std::vector<rclcpp::TopicEndpointInfo>
 NodeGraph::get_publishers_info_by_topic(
   const std::string & topic_name,
   bool no_mangle) const
 {
-  return get_info_by_topic(
+  return get_info_by_topic<const char*, rcl_get_info_by_topic_func_t>(
+    node_base_,
     topic_name,
     no_mangle,
-    "publishers",
+    "publisher",
     rcl_get_publishers_info_by_topic);
 }
 
-std::vector<rclcpp::TopicInfo>
+std::vector<rclcpp::TopicEndpointInfo>
 NodeGraph::get_subscriptions_info_by_topic(
   const std::string & topic_name,
   bool no_mangle) const
 {
-  return get_info_by_topic(
+  return get_info_by_topic<const char*, rcl_get_info_by_topic_func_t>(
+    node_base_,
     topic_name,
     no_mangle,
     "subscriptions",
diff --git a/rclcpp/test/test_node.cpp b/rclcpp/test/test_node.cpp
index b8dd3bb9a9..e8aa1f12e6 100644
--- a/rclcpp/test/test_node.cpp
+++ b/rclcpp/test/test_node.cpp
@@ -2551,8 +2551,9 @@ TEST_F(TestNode, get_publishers_subscriptions_info_by_topic) {
   // Verify publisher list has the right data.
   EXPECT_EQ(node->get_name(), publisher_list[0].node_name);
   EXPECT_EQ(node->get_namespace(), publisher_list[0].node_namespace);
-  EXPECT_EQ("test_msgs::msg::dds_::BasicTypes_", publisher_list[0].topic_type);
-  auto actual_qos_profile = publisher_list[0].qos_profile;
+  EXPECT_EQ("test_msgs/msg/BasicTypes", publisher_list[0].topic_type);
+  EXPECT_EQ(RMW_ENDPOINT_PUBLISHER, publisher_list[0].endpoint_type);
+  auto actual_qos_profile = publisher_list[0].qos.get_rmw_qos_profile();
 
   auto assert_qos_profile = [](const rmw_qos_profile_t & qos1, const rmw_qos_profile_t & qos2) {
       // Depth and history are skipped because they are not retrieved.
@@ -2605,13 +2606,15 @@ TEST_F(TestNode, get_publishers_subscriptions_info_by_topic) {
   // Verify publisher and subscription list has the right data.
   EXPECT_EQ(node->get_name(), publisher_list[0].node_name);
   EXPECT_EQ(node->get_namespace(), publisher_list[0].node_namespace);
-  EXPECT_EQ("test_msgs::msg::dds_::BasicTypes_", publisher_list[0].topic_type);
-  auto publisher_qos_profile = publisher_list[0].qos_profile;
+  EXPECT_EQ("test_msgs/msg/BasicTypes", publisher_list[0].topic_type);
+  EXPECT_EQ(RMW_ENDPOINT_PUBLISHER, publisher_list[0].endpoint_type);
+  auto publisher_qos_profile = publisher_list[0].qos.get_rmw_qos_profile();
   assert_qos_profile(qos.get_rmw_qos_profile(), publisher_qos_profile);
   EXPECT_EQ(node->get_name(), subscription_list[0].node_name);
   EXPECT_EQ(node->get_namespace(), subscription_list[0].node_namespace);
-  EXPECT_EQ("test_msgs::msg::dds_::BasicTypes_", subscription_list[0].topic_type);
-  auto subscription_qos_profile = subscription_list[0].qos_profile;
+  EXPECT_EQ("test_msgs/msg/BasicTypes", subscription_list[0].topic_type);
+  EXPECT_EQ(RMW_ENDPOINT_SUBSCRIPTION, subscription_list[0].endpoint_type);
+  auto subscription_qos_profile = subscription_list[0].qos.get_rmw_qos_profile();
   assert_qos_profile(qos2.get_rmw_qos_profile(), subscription_qos_profile);
 
   // Error cases

From 142e32a88fc3ec0c85a371cd33c6f09634071d3a Mon Sep 17 00:00:00 2001
From: Miaofei <miaofei@amazon.com>
Date: Thu, 16 Jan 2020 12:21:45 -0800
Subject: [PATCH 03/13] update templated get_info_by_topic() function

Signed-off-by: Barry Xu <Barry.Xu@sony.com>
Signed-off-by: Miaofei <miaofei@amazon.com>
---
 .../src/rclcpp/node_interfaces/node_graph.cpp | 19 ++++++-------------
 1 file changed, 6 insertions(+), 13 deletions(-)

diff --git a/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp b/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
index 758f22333a..6dea56895a 100644
--- a/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
+++ b/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
@@ -28,12 +28,6 @@
 using rclcpp::node_interfaces::NodeGraph;
 using rclcpp::exceptions::throw_from_rcl_error;
 using rclcpp::graph_listener::GraphListener;
-using rcl_get_info_by_topic_func_t = rcl_ret_t (* )(
-  const rcl_node_t *,
-  rcutils_allocator_t *,
-  const char *,
-  bool,
-  rmw_topic_endpoint_info_array_t *);
 
 NodeGraph::NodeGraph(rclcpp::node_interfaces::NodeBaseInterface * node_base)
 : node_base_(node_base),
@@ -387,13 +381,12 @@ convert_to_topic_info_list(const rmw_topic_endpoint_info_array_t & info_array)
   return topic_info_list;
 }
 
-template <typename TypeT, typename FunctionT>
+template <const char * EndpointType, typename FunctionT>
 static std::vector<rclcpp::TopicEndpointInfo>
 get_info_by_topic(
   rclcpp::node_interfaces::NodeBaseInterface * node_base,
   const std::string & topic_name,
   bool no_mangle,
-  TypeT type,
   FunctionT rcl_get_info_by_topic)
 {
   std::vector<rclcpp::TopicEndpointInfo> topic_info_list;
@@ -411,7 +404,7 @@ get_info_by_topic(
     rcl_get_info_by_topic(rcl_node_handle, &allocator, fqdn.c_str(), no_mangle, &info_array);
   if (ret != RCL_RET_OK) {
     auto error_msg =
-      std::string("Failed to get information by topic for: ") + type + std::string(":");
+      std::string("Failed to get information by topic for ") + EndpointType + std::string(":");
     if (ret == RCL_RET_UNSUPPORTED) {
       error_msg += std::string("function not supported by RMW_IMPLEMENTATION");
     } else {
@@ -435,28 +428,28 @@ get_info_by_topic(
   return topic_info_list;
 }
 
+static const char kPublisherEndpointTypeName[] = "publishers";
 std::vector<rclcpp::TopicEndpointInfo>
 NodeGraph::get_publishers_info_by_topic(
   const std::string & topic_name,
   bool no_mangle) const
 {
-  return get_info_by_topic<const char*, rcl_get_info_by_topic_func_t>(
+  return get_info_by_topic<kPublisherEndpointTypeName>(
     node_base_,
     topic_name,
     no_mangle,
-    "publisher",
     rcl_get_publishers_info_by_topic);
 }
 
+static const char kSubscriptionEndpointTypeName[] = "subscriptions";
 std::vector<rclcpp::TopicEndpointInfo>
 NodeGraph::get_subscriptions_info_by_topic(
   const std::string & topic_name,
   bool no_mangle) const
 {
-  return get_info_by_topic<const char*, rcl_get_info_by_topic_func_t>(
+  return get_info_by_topic<kSubscriptionEndpointTypeName>(
     node_base_,
     topic_name,
     no_mangle,
-    "subscriptions",
     rcl_get_subscriptions_info_by_topic);
 }

From c9ff5315b4e9aed0d97a8cfdbdc839275a040df9 Mon Sep 17 00:00:00 2001
From: Miaofei <miaofei@amazon.com>
Date: Sat, 18 Jan 2020 10:32:23 -0800
Subject: [PATCH 04/13] address some of the PR comments

Signed-off-by: Miaofei <miaofei@amazon.com>
---
 rclcpp/include/rclcpp/node.hpp                | 34 +++++++++++--------
 .../src/rclcpp/node_interfaces/node_graph.cpp |  6 ++--
 2 files changed, 23 insertions(+), 17 deletions(-)

diff --git a/rclcpp/include/rclcpp/node.hpp b/rclcpp/include/rclcpp/node.hpp
index cdd44dfce2..71d1e9a869 100644
--- a/rclcpp/include/rclcpp/node.hpp
+++ b/rclcpp/include/rclcpp/node.hpp
@@ -1078,16 +1078,19 @@ class Node : public std::enable_shared_from_this<Node>
    * the node name, node namespace, topic type, endpoint type, participant's GID and its QoS
    * profile.
    *
-   * "topic_name" may be a relative, private or fully qualified topic name.
-   * A relative or private topic will be expanded using this node's namespace and name, if
-   * the "no_mangle" param is set to false.
+   * When the `no_mangle` parameter is `true`, the provided `topic_name` should be a valid topic
+   * name for the middleware (useful when combining ROS with native middleware (e.g. DDS) apps).
+   * When the `no_mangle` parameter is `false`, the provided `topic_name` should follow
+   * ROS topic name conventions.
    *
-   * The queried topic name is not remapped.
+   * `topic_name` may be a relative, private, or fully qualified topic name.
+   * A relative or private topic will be expanded using this node's namespace and name,
+   * The queried `topic_name` is not remapped.
    *
    * \param[in] topic_name the topic_name on which to find the publishers.
-   * \param[in] no_mangle if false, the given topic name will be expanded
-   *    to its fully qualified name. Default to `false`.
-   * \return a list of TopicInfo representing all the publishers on this topic.
+   * \param[in] no_mangle if `true`, `topic_name` needs to be a valid middleware topic name,
+   *            otherwise it should be a valid ROS topic name. Defaults to `false`.
+   * \return a list of TopicEndpointInfo representing all the publishers on this topic.
    * \throws InvalidTopicNameError if the given topic_name is invalid.
    * \throws std::runtime_error if internal error happens.
    */
@@ -1101,16 +1104,19 @@ class Node : public std::enable_shared_from_this<Node>
    * the node name, node namespace, topic type, endpoint type, participant's GID and its QoS
    * profile.
    *
-   * "topic_name" may be a relative, private or fully qualified topic name.
-   * A relative or private topic will be expanded using this node's namespace and name, if
-   * the "no_mangle" param is set to false.
+   * When the `no_mangle` parameter is `true`, the provided `topic_name` should be a valid topic
+   * name for the middleware (useful when combining ROS with native middleware (e.g. DDS) apps).
+   * When the `no_mangle` parameter is `false`, the provided `topic_name` should follow
+   * ROS topic name conventions.
    *
-   * The queried topic name is not remapped.
+   * `topic_name` may be a relative, private, or fully qualified topic name.
+   * A relative or private topic will be expanded using this node's namespace and name.
+   * The queried `topic_name` is not remapped.
    *
    * \param[in] topic_name the topic_name on which to find the subscriptions.
-   * \param[in] no_mangle if false, the given topic name will be expanded
-   *    to its fully qualified name. Default to `false`.
-   * \return a list of TopicInfo representing all the subscriptions on this topic.
+   * \param[in] no_mangle if `true`, `topic_name` needs to be a valid middleware topic name,
+   *            otherwise it should be a valid ROS topic name. Defaults to `false`.
+   * \return a list of TopicEndpointInfo representing all the subscriptions on this topic.
    * \throws InvalidTopicNameError if the given topic_name is invalid.
    * \throws std::runtime_error if internal error happens.
    */
diff --git a/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp b/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
index 6dea56895a..6169caae0c 100644
--- a/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
+++ b/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
@@ -402,16 +402,16 @@ get_info_by_topic(
   rmw_topic_endpoint_info_array_t info_array = rmw_get_zero_initialized_topic_endpoint_info_array();
   auto ret =
     rcl_get_info_by_topic(rcl_node_handle, &allocator, fqdn.c_str(), no_mangle, &info_array);
-  if (ret != RCL_RET_OK) {
+  if (RCL_RET_OK != ret) {
     auto error_msg =
       std::string("Failed to get information by topic for ") + EndpointType + std::string(":");
-    if (ret == RCL_RET_UNSUPPORTED) {
+    if (RCL_RET_UNSUPPORTED == ret) {
       error_msg += std::string("function not supported by RMW_IMPLEMENTATION");
     } else {
       error_msg += rcl_get_error_string().str;
     }
     rcl_reset_error();
-    if (rmw_topic_endpoint_info_array_fini(&info_array, &allocator) != RMW_RET_OK) {
+    if (RMW_RET_OK != rmw_topic_endpoint_info_array_fini(&info_array, &allocator)) {
       error_msg += std::string(", failed also to cleanup topic info array, leaking memory: ")
         + rcl_get_error_string().str;
       rcl_reset_error();

From a79f8e40c536dee66813ec4f8137a7f4d296d0f1 Mon Sep 17 00:00:00 2001
From: Miaofei <miaofei@amazon.com>
Date: Sat, 18 Jan 2020 10:51:45 -0800
Subject: [PATCH 05/13] change rclcpp::EndpointType to an enum class

Signed-off-by: Miaofei <miaofei@amazon.com>
---
 .../rclcpp/node_interfaces/node_graph_interface.hpp      | 9 +++++++--
 rclcpp/test/test_node.cpp                                | 6 +++---
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp b/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
index 1cd6cf8325..5a8f0f9165 100644
--- a/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
+++ b/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
@@ -33,7 +33,12 @@
 namespace rclcpp
 {
 
-using EndpointType = rmw_endpoint_type_t;
+enum class EndpointType
+{
+  Invalid = RMW_ENDPOINT_INVALID,
+  Publisher = RMW_ENDPOINT_PUBLISHER,
+  Subscription = RMW_ENDPOINT_SUBSCRIPTION
+};
 
 /**
  * Use to get topic endpoint information that containing the node name, node namespace, topic type,
@@ -53,7 +58,7 @@ struct RCLCPP_PUBLIC TopicEndpointInfo
   : node_name(info.node_name),
     node_namespace(info.node_namespace),
     topic_type(info.topic_type),
-    endpoint_type(info.endpoint_type),
+    endpoint_type(static_cast<rclcpp::EndpointType>(info.endpoint_type)),
     qos({info.qos_profile.history, info.qos_profile.depth}, info.qos_profile)
   {
     std::copy(info.endpoint_gid, info.endpoint_gid+RMW_GID_STORAGE_SIZE, endpoint_gid.begin());
diff --git a/rclcpp/test/test_node.cpp b/rclcpp/test/test_node.cpp
index e8aa1f12e6..e90dedf846 100644
--- a/rclcpp/test/test_node.cpp
+++ b/rclcpp/test/test_node.cpp
@@ -2552,7 +2552,7 @@ TEST_F(TestNode, get_publishers_subscriptions_info_by_topic) {
   EXPECT_EQ(node->get_name(), publisher_list[0].node_name);
   EXPECT_EQ(node->get_namespace(), publisher_list[0].node_namespace);
   EXPECT_EQ("test_msgs/msg/BasicTypes", publisher_list[0].topic_type);
-  EXPECT_EQ(RMW_ENDPOINT_PUBLISHER, publisher_list[0].endpoint_type);
+  EXPECT_EQ(rclcpp::EndpointType::Publisher, publisher_list[0].endpoint_type);
   auto actual_qos_profile = publisher_list[0].qos.get_rmw_qos_profile();
 
   auto assert_qos_profile = [](const rmw_qos_profile_t & qos1, const rmw_qos_profile_t & qos2) {
@@ -2607,13 +2607,13 @@ TEST_F(TestNode, get_publishers_subscriptions_info_by_topic) {
   EXPECT_EQ(node->get_name(), publisher_list[0].node_name);
   EXPECT_EQ(node->get_namespace(), publisher_list[0].node_namespace);
   EXPECT_EQ("test_msgs/msg/BasicTypes", publisher_list[0].topic_type);
-  EXPECT_EQ(RMW_ENDPOINT_PUBLISHER, publisher_list[0].endpoint_type);
+  EXPECT_EQ(rclcpp::EndpointType::Publisher, publisher_list[0].endpoint_type);
   auto publisher_qos_profile = publisher_list[0].qos.get_rmw_qos_profile();
   assert_qos_profile(qos.get_rmw_qos_profile(), publisher_qos_profile);
   EXPECT_EQ(node->get_name(), subscription_list[0].node_name);
   EXPECT_EQ(node->get_namespace(), subscription_list[0].node_namespace);
   EXPECT_EQ("test_msgs/msg/BasicTypes", subscription_list[0].topic_type);
-  EXPECT_EQ(RMW_ENDPOINT_SUBSCRIPTION, subscription_list[0].endpoint_type);
+  EXPECT_EQ(rclcpp::EndpointType::Subscription, subscription_list[0].endpoint_type);
   auto subscription_qos_profile = subscription_list[0].qos.get_rmw_qos_profile();
   assert_qos_profile(qos2.get_rmw_qos_profile(), subscription_qos_profile);
 

From 4db2a3114da9a8b3683526b5bb6ce7ef421c10fd Mon Sep 17 00:00:00 2001
From: Miaofei <miaofei@amazon.com>
Date: Mon, 20 Jan 2020 14:01:29 -0800
Subject: [PATCH 06/13] fix punctuation in docstring

Signed-off-by: Miaofei <miaofei@amazon.com>
---
 rclcpp/include/rclcpp/node.hpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/rclcpp/include/rclcpp/node.hpp b/rclcpp/include/rclcpp/node.hpp
index 71d1e9a869..f9496ff645 100644
--- a/rclcpp/include/rclcpp/node.hpp
+++ b/rclcpp/include/rclcpp/node.hpp
@@ -1084,7 +1084,7 @@ class Node : public std::enable_shared_from_this<Node>
    * ROS topic name conventions.
    *
    * `topic_name` may be a relative, private, or fully qualified topic name.
-   * A relative or private topic will be expanded using this node's namespace and name,
+   * A relative or private topic will be expanded using this node's namespace and name.
    * The queried `topic_name` is not remapped.
    *
    * \param[in] topic_name the topic_name on which to find the publishers.

From 67ca5b82558b71ee0d824d3214f7c70c3dbb1814 Mon Sep 17 00:00:00 2001
From: Miaofei <miaofei@amazon.com>
Date: Tue, 21 Jan 2020 14:31:19 -0800
Subject: [PATCH 07/13] address more PR comments

Signed-off-by: Miaofei <miaofei@amazon.com>
---
 rclcpp/include/rclcpp/node.hpp                   | 12 ++++++------
 .../node_interfaces/node_graph_interface.hpp     | 16 ++++++++--------
 rclcpp/src/rclcpp/node_interfaces/node_graph.cpp | 12 ++++++------
 3 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/rclcpp/include/rclcpp/node.hpp b/rclcpp/include/rclcpp/node.hpp
index f9496ff645..21e918fc41 100644
--- a/rclcpp/include/rclcpp/node.hpp
+++ b/rclcpp/include/rclcpp/node.hpp
@@ -1072,10 +1072,10 @@ class Node : public std::enable_shared_from_this<Node>
   bool
   assert_liveliness() const;
 
-  /// Return a list of publishers about topic endpoint information to a given topic.
+  /// Return the topic endpoint information about publishers on a given topic.
   /**
    * The returned parameter is a list of topic endpoint information, where each item will contain
-   * the node name, node namespace, topic type, endpoint type, participant's GID and its QoS
+   * the node name, node namespace, topic type, endpoint type, topic endpoint's GID, and its QoS
    * profile.
    *
    * When the `no_mangle` parameter is `true`, the provided `topic_name` should be a valid topic
@@ -1089,7 +1089,7 @@ class Node : public std::enable_shared_from_this<Node>
    *
    * \param[in] topic_name the topic_name on which to find the publishers.
    * \param[in] no_mangle if `true`, `topic_name` needs to be a valid middleware topic name,
-   *            otherwise it should be a valid ROS topic name. Defaults to `false`.
+   *   otherwise it should be a valid ROS topic name. Defaults to `false`.
    * \return a list of TopicEndpointInfo representing all the publishers on this topic.
    * \throws InvalidTopicNameError if the given topic_name is invalid.
    * \throws std::runtime_error if internal error happens.
@@ -1098,10 +1098,10 @@ class Node : public std::enable_shared_from_this<Node>
   std::vector<rclcpp::TopicEndpointInfo>
   get_publishers_info_by_topic(const std::string & topic_name, bool no_mangle = false) const;
 
-  /// Return a list of subscriptions about topic endpoint information to a given topic.
+  /// Return the topic endpoint information about subscriptions on a given topic.
   /**
    * The returned parameter is a list of topic endpoint information, where each item will contain
-   * the node name, node namespace, topic type, endpoint type, participant's GID and its QoS
+   * the node name, node namespace, topic type, endpoint type, topic endpoint's GID, and its QoS
    * profile.
    *
    * When the `no_mangle` parameter is `true`, the provided `topic_name` should be a valid topic
@@ -1115,7 +1115,7 @@ class Node : public std::enable_shared_from_this<Node>
    *
    * \param[in] topic_name the topic_name on which to find the subscriptions.
    * \param[in] no_mangle if `true`, `topic_name` needs to be a valid middleware topic name,
-   *            otherwise it should be a valid ROS topic name. Defaults to `false`.
+   *   otherwise it should be a valid ROS topic name. Defaults to `false`.
    * \return a list of TopicEndpointInfo representing all the subscriptions on this topic.
    * \throws InvalidTopicNameError if the given topic_name is invalid.
    * \throws std::runtime_error if internal error happens.
diff --git a/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp b/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
index 5a8f0f9165..4283f97b55 100644
--- a/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
+++ b/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
@@ -22,13 +22,13 @@
 #include <utility>
 #include <vector>
 
+#include "rcl/graph.h"
 #include "rcl/guard_condition.h"
 
 #include "rclcpp/event.hpp"
 #include "rclcpp/macros.hpp"
 #include "rclcpp/qos.hpp"
 #include "rclcpp/visibility_control.hpp"
-#include "rmw/topic_endpoint_info.h"
 
 namespace rclcpp
 {
@@ -41,8 +41,8 @@ enum class EndpointType
 };
 
 /**
- * Use to get topic endpoint information that containing the node name, node namespace, topic type,
- * endpoint type, GID of endpoint and its QoS.
+ * "Struct that contains topic endpoint information like the associated node name, node namespace,
+ * topic type, endpoint type, endpoint GID, and its QoS.
  */
 struct RCLCPP_PUBLIC TopicEndpointInfo
 {
@@ -53,15 +53,15 @@ struct RCLCPP_PUBLIC TopicEndpointInfo
   std::array<uint8_t, RMW_GID_STORAGE_SIZE> endpoint_gid;
   rclcpp::QoS qos;
 
-  /// Constructor which convert rmw_topic_endpoint_info_t to TopicEndpointInfo.
-  TopicEndpointInfo(const rmw_topic_endpoint_info_t & info)
+  /// Constructor which converts rcl_topic_endpoint_info_t to TopicEndpointInfo.
+  TopicEndpointInfo(const rcl_topic_endpoint_info_t & info)
   : node_name(info.node_name),
     node_namespace(info.node_namespace),
     topic_type(info.topic_type),
     endpoint_type(static_cast<rclcpp::EndpointType>(info.endpoint_type)),
     qos({info.qos_profile.history, info.qos_profile.depth}, info.qos_profile)
   {
-    std::copy(info.endpoint_gid, info.endpoint_gid+RMW_GID_STORAGE_SIZE, endpoint_gid.begin());
+    std::copy(info.endpoint_gid, info.endpoint_gid + RMW_GID_STORAGE_SIZE, endpoint_gid.begin());
   }
 };
 
@@ -187,7 +187,7 @@ class NodeGraphInterface
   size_t
   count_graph_users() = 0;
 
-  /// Return a list of publishers about topic endpoint information to a given topic.
+  /// Return the topic endpoint information about publishers on a given topic.
   /**
    * \sa rclcpp::Node::get_publishers_info_by_topic
    */
@@ -196,7 +196,7 @@ class NodeGraphInterface
   std::vector<rclcpp::TopicEndpointInfo>
   get_publishers_info_by_topic(const std::string & topic_name, bool no_mangle = false) const = 0;
 
-  /// Return a list of subscriptions about topic endpoint information to a given topic.
+  /// Return the topic endpoint information about subscriptions on a given topic.
   /**
    * \sa rclcpp::Node::get_subscriptions_info_by_topic
    */
diff --git a/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp b/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
index 6169caae0c..543ef533df 100644
--- a/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
+++ b/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
@@ -372,7 +372,7 @@ NodeGraph::count_graph_users()
 
 static
 std::vector<rclcpp::TopicEndpointInfo>
-convert_to_topic_info_list(const rmw_topic_endpoint_info_array_t & info_array)
+convert_to_topic_info_list(const rcl_topic_endpoint_info_array_t & info_array)
 {
   std::vector<rclcpp::TopicEndpointInfo> topic_info_list;
   for (size_t i = 0; i < info_array.count; ++i) {
@@ -399,7 +399,7 @@ get_info_by_topic(
     false);    // false = not a service
 
   rcutils_allocator_t allocator = rcutils_get_default_allocator();
-  rmw_topic_endpoint_info_array_t info_array = rmw_get_zero_initialized_topic_endpoint_info_array();
+  rcl_topic_endpoint_info_array_t info_array = rcl_get_zero_initialized_topic_endpoint_info_array();
   auto ret =
     rcl_get_info_by_topic(rcl_node_handle, &allocator, fqdn.c_str(), no_mangle, &info_array);
   if (RCL_RET_OK != ret) {
@@ -411,7 +411,7 @@ get_info_by_topic(
       error_msg += rcl_get_error_string().str;
     }
     rcl_reset_error();
-    if (RMW_RET_OK != rmw_topic_endpoint_info_array_fini(&info_array, &allocator)) {
+    if (RCL_RET_OK != rcl_topic_endpoint_info_array_fini(&info_array, &allocator)) {
       error_msg += std::string(", failed also to cleanup topic info array, leaking memory: ")
         + rcl_get_error_string().str;
       rcl_reset_error();
@@ -420,9 +420,9 @@ get_info_by_topic(
   }
 
   topic_info_list = convert_to_topic_info_list(info_array);
-  ret = rmw_topic_endpoint_info_array_fini(&info_array, &allocator);
-  if (ret != RMW_RET_OK) {
-    throw_from_rcl_error(ret, "rmw_topic_info_array_fini failed.");
+  ret = rcl_topic_endpoint_info_array_fini(&info_array, &allocator);
+  if (RCL_RET_OK != ret) {
+    throw_from_rcl_error(ret, "rcl_topic_info_array_fini failed.");
   }
 
   return topic_info_list;

From 88af887b27f77c92a974918c52fb11485355ce00 Mon Sep 17 00:00:00 2001
From: Miaofei <miaofei@amazon.com>
Date: Thu, 23 Jan 2020 07:45:07 -0800
Subject: [PATCH 08/13] add get_publishers/subscriptions_info_by_topic() to
 LifecycleNode

Signed-off-by: Miaofei <miaofei@amazon.com>
---
 rclcpp/include/rclcpp/node.hpp                | 104 +++++++++---------
 rclcpp/src/rclcpp/node.cpp                    |  24 ++--
 .../rclcpp_lifecycle/lifecycle_node.hpp       |  16 +++
 rclcpp_lifecycle/src/lifecycle_node.cpp       |  12 ++
 4 files changed, 92 insertions(+), 64 deletions(-)

diff --git a/rclcpp/include/rclcpp/node.hpp b/rclcpp/include/rclcpp/node.hpp
index 21e918fc41..b9398f567c 100644
--- a/rclcpp/include/rclcpp/node.hpp
+++ b/rclcpp/include/rclcpp/node.hpp
@@ -867,6 +867,58 @@ class Node : public std::enable_shared_from_this<Node>
   size_t
   count_subscribers(const std::string & topic_name) const;
 
+  /// Return the topic endpoint information about publishers on a given topic.
+  /**
+   * The returned parameter is a list of topic endpoint information, where each item will contain
+   * the node name, node namespace, topic type, endpoint type, topic endpoint's GID, and its QoS
+   * profile.
+   *
+   * When the `no_mangle` parameter is `true`, the provided `topic_name` should be a valid topic
+   * name for the middleware (useful when combining ROS with native middleware (e.g. DDS) apps).
+   * When the `no_mangle` parameter is `false`, the provided `topic_name` should follow
+   * ROS topic name conventions.
+   *
+   * `topic_name` may be a relative, private, or fully qualified topic name.
+   * A relative or private topic will be expanded using this node's namespace and name.
+   * The queried `topic_name` is not remapped.
+   *
+   * \param[in] topic_name the topic_name on which to find the publishers.
+   * \param[in] no_mangle if `true`, `topic_name` needs to be a valid middleware topic name,
+   *   otherwise it should be a valid ROS topic name. Defaults to `false`.
+   * \return a list of TopicEndpointInfo representing all the publishers on this topic.
+   * \throws InvalidTopicNameError if the given topic_name is invalid.
+   * \throws std::runtime_error if internal error happens.
+   */
+  RCLCPP_PUBLIC
+  std::vector<rclcpp::TopicEndpointInfo>
+  get_publishers_info_by_topic(const std::string & topic_name, bool no_mangle = false) const;
+
+  /// Return the topic endpoint information about subscriptions on a given topic.
+  /**
+   * The returned parameter is a list of topic endpoint information, where each item will contain
+   * the node name, node namespace, topic type, endpoint type, topic endpoint's GID, and its QoS
+   * profile.
+   *
+   * When the `no_mangle` parameter is `true`, the provided `topic_name` should be a valid topic
+   * name for the middleware (useful when combining ROS with native middleware (e.g. DDS) apps).
+   * When the `no_mangle` parameter is `false`, the provided `topic_name` should follow
+   * ROS topic name conventions.
+   *
+   * `topic_name` may be a relative, private, or fully qualified topic name.
+   * A relative or private topic will be expanded using this node's namespace and name.
+   * The queried `topic_name` is not remapped.
+   *
+   * \param[in] topic_name the topic_name on which to find the subscriptions.
+   * \param[in] no_mangle if `true`, `topic_name` needs to be a valid middleware topic name,
+   *   otherwise it should be a valid ROS topic name. Defaults to `false`.
+   * \return a list of TopicEndpointInfo representing all the subscriptions on this topic.
+   * \throws InvalidTopicNameError if the given topic_name is invalid.
+   * \throws std::runtime_error if internal error happens.
+   */
+  RCLCPP_PUBLIC
+  std::vector<rclcpp::TopicEndpointInfo>
+  get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle = false) const;
+
   /// Return a graph event, which will be set anytime a graph change occurs.
   /* The graph Event object is a loan which must be returned.
    * The Event object is scoped and therefore to return the loan just let it go
@@ -1072,58 +1124,6 @@ class Node : public std::enable_shared_from_this<Node>
   bool
   assert_liveliness() const;
 
-  /// Return the topic endpoint information about publishers on a given topic.
-  /**
-   * The returned parameter is a list of topic endpoint information, where each item will contain
-   * the node name, node namespace, topic type, endpoint type, topic endpoint's GID, and its QoS
-   * profile.
-   *
-   * When the `no_mangle` parameter is `true`, the provided `topic_name` should be a valid topic
-   * name for the middleware (useful when combining ROS with native middleware (e.g. DDS) apps).
-   * When the `no_mangle` parameter is `false`, the provided `topic_name` should follow
-   * ROS topic name conventions.
-   *
-   * `topic_name` may be a relative, private, or fully qualified topic name.
-   * A relative or private topic will be expanded using this node's namespace and name.
-   * The queried `topic_name` is not remapped.
-   *
-   * \param[in] topic_name the topic_name on which to find the publishers.
-   * \param[in] no_mangle if `true`, `topic_name` needs to be a valid middleware topic name,
-   *   otherwise it should be a valid ROS topic name. Defaults to `false`.
-   * \return a list of TopicEndpointInfo representing all the publishers on this topic.
-   * \throws InvalidTopicNameError if the given topic_name is invalid.
-   * \throws std::runtime_error if internal error happens.
-   */
-  RCLCPP_PUBLIC
-  std::vector<rclcpp::TopicEndpointInfo>
-  get_publishers_info_by_topic(const std::string & topic_name, bool no_mangle = false) const;
-
-  /// Return the topic endpoint information about subscriptions on a given topic.
-  /**
-   * The returned parameter is a list of topic endpoint information, where each item will contain
-   * the node name, node namespace, topic type, endpoint type, topic endpoint's GID, and its QoS
-   * profile.
-   *
-   * When the `no_mangle` parameter is `true`, the provided `topic_name` should be a valid topic
-   * name for the middleware (useful when combining ROS with native middleware (e.g. DDS) apps).
-   * When the `no_mangle` parameter is `false`, the provided `topic_name` should follow
-   * ROS topic name conventions.
-   *
-   * `topic_name` may be a relative, private, or fully qualified topic name.
-   * A relative or private topic will be expanded using this node's namespace and name.
-   * The queried `topic_name` is not remapped.
-   *
-   * \param[in] topic_name the topic_name on which to find the subscriptions.
-   * \param[in] no_mangle if `true`, `topic_name` needs to be a valid middleware topic name,
-   *   otherwise it should be a valid ROS topic name. Defaults to `false`.
-   * \return a list of TopicEndpointInfo representing all the subscriptions on this topic.
-   * \throws InvalidTopicNameError if the given topic_name is invalid.
-   * \throws std::runtime_error if internal error happens.
-   */
-  RCLCPP_PUBLIC
-  std::vector<rclcpp::TopicEndpointInfo>
-  get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle = false) const;
-
 protected:
   /// Construct a sub-node, which will extend the namespace of all entities created with it.
   /**
diff --git a/rclcpp/src/rclcpp/node.cpp b/rclcpp/src/rclcpp/node.cpp
index 0d65f2b686..a2bf2707d2 100644
--- a/rclcpp/src/rclcpp/node.cpp
+++ b/rclcpp/src/rclcpp/node.cpp
@@ -364,6 +364,18 @@ Node::count_subscribers(const std::string & topic_name) const
   return node_graph_->count_subscribers(topic_name);
 }
 
+std::vector<rclcpp::TopicEndpointInfo>
+Node::get_publishers_info_by_topic(const std::string & topic_name, bool no_mangle) const
+{
+  return node_graph_->get_publishers_info_by_topic(topic_name, no_mangle);
+}
+
+std::vector<rclcpp::TopicEndpointInfo>
+Node::get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle) const
+{
+  return node_graph_->get_subscriptions_info_by_topic(topic_name, no_mangle);
+}
+
 const std::vector<rclcpp::callback_group::CallbackGroup::WeakPtr> &
 Node::get_callback_groups() const
 {
@@ -493,15 +505,3 @@ Node::assert_liveliness() const
 {
   return node_base_->assert_liveliness();
 }
-
-std::vector<rclcpp::TopicEndpointInfo>
-Node::get_publishers_info_by_topic(const std::string & topic_name, bool no_mangle) const
-{
-  return node_graph_->get_publishers_info_by_topic(topic_name, no_mangle);
-}
-
-std::vector<rclcpp::TopicEndpointInfo>
-Node::get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle) const
-{
-  return node_graph_->get_subscriptions_info_by_topic(topic_name, no_mangle);
-}
diff --git a/rclcpp_lifecycle/include/rclcpp_lifecycle/lifecycle_node.hpp b/rclcpp_lifecycle/include/rclcpp_lifecycle/lifecycle_node.hpp
index 6ed96db535..6b6c213fd5 100644
--- a/rclcpp_lifecycle/include/rclcpp_lifecycle/lifecycle_node.hpp
+++ b/rclcpp_lifecycle/include/rclcpp_lifecycle/lifecycle_node.hpp
@@ -439,6 +439,22 @@ class LifecycleNode : public node_interfaces::LifecycleNodeInterface,
   size_t
   count_subscribers(const std::string & topic_name) const;
 
+  /// Return the topic endpoint information about publishers on a given topic.
+  /**
+   * \sa rclcpp::Node::get_publishers_info_by_topic
+   */
+  RCLCPP_LIFECYCLE_PUBLIC
+  std::vector<rclcpp::TopicEndpointInfo>
+  get_publishers_info_by_topic(const std::string & topic_name, bool no_mangle = false) const;
+
+  /// Return the topic endpoint information about subscriptions on a given topic.
+  /**
+   * \sa rclcpp::Node::get_subscriptions_info_by_topic
+   */
+  RCLCPP_LIFECYCLE_PUBLIC
+  std::vector<rclcpp::TopicEndpointInfo>
+  get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle = false) const;
+
   /// Return a graph event, which will be set anytime a graph change occurs.
   /* The graph Event object is a loan which must be returned.
    * The Event object is scoped and therefore to return the load just let it go
diff --git a/rclcpp_lifecycle/src/lifecycle_node.cpp b/rclcpp_lifecycle/src/lifecycle_node.cpp
index f75d6c2e44..973ec04270 100644
--- a/rclcpp_lifecycle/src/lifecycle_node.cpp
+++ b/rclcpp_lifecycle/src/lifecycle_node.cpp
@@ -290,6 +290,18 @@ LifecycleNode::count_subscribers(const std::string & topic_name) const
   return node_graph_->count_subscribers(topic_name);
 }
 
+std::vector<rclcpp::TopicEndpointInfo>
+LifecycleNode::get_publishers_info_by_topic(const std::string & topic_name, bool no_mangle) const
+{
+  return node_graph_->get_publishers_info_by_topic(topic_name, no_mangle);
+}
+
+std::vector<rclcpp::TopicEndpointInfo>
+LifecycleNode::get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle) const
+{
+  return node_graph_->get_subscriptions_info_by_topic(topic_name, no_mangle);
+}
+
 const std::vector<rclcpp::callback_group::CallbackGroup::WeakPtr> &
 LifecycleNode::get_callback_groups() const
 {

From 814117c587a363a04cf586724b0e8a75bcc53633 Mon Sep 17 00:00:00 2001
From: Miaofei <miaofei@amazon.com>
Date: Thu, 23 Jan 2020 08:14:44 -0800
Subject: [PATCH 09/13] remove weird punctuation from docstring

Signed-off-by: Miaofei <miaofei@amazon.com>
---
 rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp b/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
index 4283f97b55..78322f866b 100644
--- a/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
+++ b/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
@@ -41,7 +41,7 @@ enum class EndpointType
 };
 
 /**
- * "Struct that contains topic endpoint information like the associated node name, node namespace,
+ * Struct that contains topic endpoint information like the associated node name, node namespace,
  * topic type, endpoint type, endpoint GID, and its QoS.
  */
 struct RCLCPP_PUBLIC TopicEndpointInfo

From 634d588723b386ff7c1bf7128d292f25be7447ad Mon Sep 17 00:00:00 2001
From: Miaofei <miaofei@amazon.com>
Date: Fri, 31 Jan 2020 11:34:17 -0800
Subject: [PATCH 10/13] add topic name remapping to get_info_by_topic()

Signed-off-by: Miaofei <miaofei@amazon.com>
---
 .../node_interfaces/node_graph_interface.hpp  |  3 +-
 .../src/rclcpp/node_interfaces/node_graph.cpp | 60 +++++++++++++++----
 2 files changed, 49 insertions(+), 14 deletions(-)

diff --git a/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp b/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
index 78322f866b..9ec70eb83f 100644
--- a/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
+++ b/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
@@ -15,6 +15,7 @@
 #ifndef RCLCPP__NODE_INTERFACES__NODE_GRAPH_INTERFACE_HPP_
 #define RCLCPP__NODE_INTERFACES__NODE_GRAPH_INTERFACE_HPP_
 
+#include <algorithm>
 #include <array>
 #include <chrono>
 #include <map>
@@ -54,7 +55,7 @@ struct RCLCPP_PUBLIC TopicEndpointInfo
   rclcpp::QoS qos;
 
   /// Constructor which converts rcl_topic_endpoint_info_t to TopicEndpointInfo.
-  TopicEndpointInfo(const rcl_topic_endpoint_info_t & info)
+  explicit TopicEndpointInfo(const rcl_topic_endpoint_info_t & info)
   : node_name(info.node_name),
     node_namespace(info.node_namespace),
     topic_type(info.topic_type),
diff --git a/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp b/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
index 543ef533df..bca5d1770c 100644
--- a/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
+++ b/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
@@ -21,8 +21,9 @@
 #include <vector>
 
 #include "rcl/graph.h"
-#include "rclcpp/exceptions.hpp"
+#include "rcl/remap.h"
 #include "rclcpp/event.hpp"
+#include "rclcpp/exceptions.hpp"
 #include "rclcpp/graph_listener.hpp"
 
 using rclcpp::node_interfaces::NodeGraph;
@@ -381,7 +382,7 @@ convert_to_topic_info_list(const rcl_topic_endpoint_info_array_t & info_array)
   return topic_info_list;
 }
 
-template <const char * EndpointType, typename FunctionT>
+template<const char * EndpointType, typename FunctionT>
 static std::vector<rclcpp::TopicEndpointInfo>
 get_info_by_topic(
   rclcpp::node_interfaces::NodeBaseInterface * node_base,
@@ -389,18 +390,51 @@ get_info_by_topic(
   bool no_mangle,
   FunctionT rcl_get_info_by_topic)
 {
-  std::vector<rclcpp::TopicEndpointInfo> topic_info_list;
-
+  std::string fqdn;
   auto rcl_node_handle = node_base->get_rcl_node_handle();
-  auto fqdn = rclcpp::expand_topic_or_service_name(
-    topic_name,
-    rcl_node_get_name(rcl_node_handle),
-    rcl_node_get_namespace(rcl_node_handle),
-    false);    // false = not a service
+
+  if (no_mangle) {
+    fqdn = topic_name;
+  } else {
+    fqdn = rclcpp::expand_topic_or_service_name(
+      topic_name,
+      rcl_node_get_name(rcl_node_handle),
+      rcl_node_get_namespace(rcl_node_handle),
+      false);    // false = not a service
+
+    // Get the node options
+    const rcl_node_options_t * node_options = rcl_node_get_options(rcl_node_handle);
+    if (nullptr == node_options) {
+      throw std::runtime_error("Need valid node options in get_info_by_topic()");
+    }
+
+    // global before local so that local overwrites global
+    const rcl_arguments_t * global_args = nullptr;
+    if (node_options->use_global_arguments) {
+      auto context_ptr = node_base->get_context()->get_rcl_context();
+      global_args = &(rcl_node_handle->context->global_arguments);
+    }
+
+    char * remapped_topic_name = nullptr;
+    rcl_ret_t ret = rcl_remap_topic_name(
+      &(node_options->arguments),
+      global_args,
+      fqdn.c_str(),
+      rcl_node_get_name(rcl_node_handle),
+      rcl_node_get_namespace(rcl_node_handle),
+      node_options->allocator,
+      &remapped_topic_name);
+    if (RCL_RET_OK != ret) {
+      throw_from_rcl_error(ret, std::string("Failed to remap topic name ") + fqdn);
+    } else if (nullptr != remapped_topic_name) {
+      fqdn = remapped_topic_name;
+      node_options->allocator.deallocate(remapped_topic_name, node_options->allocator.state);
+    }
+  }
 
   rcutils_allocator_t allocator = rcutils_get_default_allocator();
   rcl_topic_endpoint_info_array_t info_array = rcl_get_zero_initialized_topic_endpoint_info_array();
-  auto ret =
+  rcl_ret_t ret =
     rcl_get_info_by_topic(rcl_node_handle, &allocator, fqdn.c_str(), no_mangle, &info_array);
   if (RCL_RET_OK != ret) {
     auto error_msg =
@@ -412,14 +446,14 @@ get_info_by_topic(
     }
     rcl_reset_error();
     if (RCL_RET_OK != rcl_topic_endpoint_info_array_fini(&info_array, &allocator)) {
-      error_msg += std::string(", failed also to cleanup topic info array, leaking memory: ")
-        + rcl_get_error_string().str;
+      error_msg += std::string(", failed also to cleanup topic info array, leaking memory: ") +
+        rcl_get_error_string().str;
       rcl_reset_error();
     }
     throw_from_rcl_error(ret, error_msg);
   }
 
-  topic_info_list = convert_to_topic_info_list(info_array);
+  std::vector<rclcpp::TopicEndpointInfo> topic_info_list = convert_to_topic_info_list(info_array);
   ret = rcl_topic_endpoint_info_array_fini(&info_array, &allocator);
   if (RCL_RET_OK != ret) {
     throw_from_rcl_error(ret, "rcl_topic_info_array_fini failed.");

From bc1b891b6394ce90259ad8f6963641e4f41222e3 Mon Sep 17 00:00:00 2001
From: Miaofei <miaofei@amazon.com>
Date: Fri, 7 Feb 2020 02:38:01 -0800
Subject: [PATCH 11/13] remove useless line of code

Signed-off-by: Miaofei <miaofei@amazon.com>
---
 rclcpp/src/rclcpp/node_interfaces/node_graph.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp b/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
index bca5d1770c..675d2d3af0 100644
--- a/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
+++ b/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
@@ -411,7 +411,6 @@ get_info_by_topic(
     // global before local so that local overwrites global
     const rcl_arguments_t * global_args = nullptr;
     if (node_options->use_global_arguments) {
-      auto context_ptr = node_base->get_context()->get_rcl_context();
       global_args = &(rcl_node_handle->context->global_arguments);
     }
 

From 9911d2404894b17546d4e14fa30cc721072cb143 Mon Sep 17 00:00:00 2001
From: Miaofei <miaofei@amazon.com>
Date: Fri, 7 Feb 2020 10:23:35 -0800
Subject: [PATCH 12/13] remove non-applicable comment

Signed-off-by: Miaofei <miaofei@amazon.com>
---
 rclcpp/src/rclcpp/node_interfaces/node_graph.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp b/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
index 675d2d3af0..286022ec3e 100644
--- a/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
+++ b/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
@@ -407,8 +407,6 @@ get_info_by_topic(
     if (nullptr == node_options) {
       throw std::runtime_error("Need valid node options in get_info_by_topic()");
     }
-
-    // global before local so that local overwrites global
     const rcl_arguments_t * global_args = nullptr;
     if (node_options->use_global_arguments) {
       global_args = &(rcl_node_handle->context->global_arguments);

From cb064f2f297ffaa4f097e5d7f9a0d5c81ad663ef Mon Sep 17 00:00:00 2001
From: Miaofei <miaofei@amazon.com>
Date: Tue, 11 Feb 2020 13:42:14 -0800
Subject: [PATCH 13/13] make members of TopicEndpointInfo private

Signed-off-by: Miaofei <miaofei@amazon.com>
---
 .../node_interfaces/node_graph_interface.hpp  | 93 ++++++++++++++++---
 .../src/rclcpp/node_interfaces/node_graph.cpp | 73 +++++++++++++++
 rclcpp/test/test_node.cpp                     | 30 +++---
 3 files changed, 166 insertions(+), 30 deletions(-)

diff --git a/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp b/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
index 9ec70eb83f..26ab3118ef 100644
--- a/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
+++ b/rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
@@ -45,25 +45,88 @@ enum class EndpointType
  * Struct that contains topic endpoint information like the associated node name, node namespace,
  * topic type, endpoint type, endpoint GID, and its QoS.
  */
-struct RCLCPP_PUBLIC TopicEndpointInfo
+class TopicEndpointInfo
 {
-  std::string node_name;
-  std::string node_namespace;
-  std::string topic_type;
-  rclcpp::EndpointType endpoint_type;
-  std::array<uint8_t, RMW_GID_STORAGE_SIZE> endpoint_gid;
-  rclcpp::QoS qos;
-
-  /// Constructor which converts rcl_topic_endpoint_info_t to TopicEndpointInfo.
+public:
+  /// Construct a TopicEndpointInfo from a rcl_topic_endpoint_info_t.
+  RCLCPP_PUBLIC
   explicit TopicEndpointInfo(const rcl_topic_endpoint_info_t & info)
-  : node_name(info.node_name),
-    node_namespace(info.node_namespace),
-    topic_type(info.topic_type),
-    endpoint_type(static_cast<rclcpp::EndpointType>(info.endpoint_type)),
-    qos({info.qos_profile.history, info.qos_profile.depth}, info.qos_profile)
+  : node_name_(info.node_name),
+    node_namespace_(info.node_namespace),
+    topic_type_(info.topic_type),
+    endpoint_type_(static_cast<rclcpp::EndpointType>(info.endpoint_type)),
+    qos_profile_({info.qos_profile.history, info.qos_profile.depth}, info.qos_profile)
   {
-    std::copy(info.endpoint_gid, info.endpoint_gid + RMW_GID_STORAGE_SIZE, endpoint_gid.begin());
+    std::copy(info.endpoint_gid, info.endpoint_gid + RMW_GID_STORAGE_SIZE, endpoint_gid_.begin());
   }
+
+  /// Get a mutable reference to the node name.
+  RCLCPP_PUBLIC
+  std::string &
+  node_name();
+
+  /// Get a const reference to the node name.
+  RCLCPP_PUBLIC
+  const std::string &
+  node_name() const;
+
+  /// Get a mutable reference to the node namespace.
+  RCLCPP_PUBLIC
+  std::string &
+  node_namespace();
+
+  /// Get a const reference to the node namespace.
+  RCLCPP_PUBLIC
+  const std::string &
+  node_namespace() const;
+
+  /// Get a mutable reference to the topic type string.
+  RCLCPP_PUBLIC
+  std::string &
+  topic_type();
+
+  /// Get a const reference to the topic type string.
+  RCLCPP_PUBLIC
+  const std::string &
+  topic_type() const;
+
+  /// Get a mutable reference to the topic endpoint type.
+  RCLCPP_PUBLIC
+  rclcpp::EndpointType &
+  endpoint_type();
+
+  /// Get a const reference to the topic endpoint type.
+  RCLCPP_PUBLIC
+  const rclcpp::EndpointType &
+  endpoint_type() const;
+
+  /// Get a mutable reference to the GID of the topic endpoint.
+  RCLCPP_PUBLIC
+  std::array<uint8_t, RMW_GID_STORAGE_SIZE> &
+  endpoint_gid();
+
+  /// Get a const reference to the GID of the topic endpoint.
+  RCLCPP_PUBLIC
+  const std::array<uint8_t, RMW_GID_STORAGE_SIZE> &
+  endpoint_gid() const;
+
+  /// Get a mutable reference to the QoS profile of the topic endpoint.
+  RCLCPP_PUBLIC
+  rclcpp::QoS &
+  qos_profile();
+
+  /// Get a const reference to the QoS profile of the topic endpoint.
+  RCLCPP_PUBLIC
+  const rclcpp::QoS &
+  qos_profile() const;
+
+private:
+  std::string node_name_;
+  std::string node_namespace_;
+  std::string topic_type_;
+  rclcpp::EndpointType endpoint_type_;
+  std::array<uint8_t, RMW_GID_STORAGE_SIZE> endpoint_gid_;
+  rclcpp::QoS qos_profile_;
 };
 
 namespace node_interfaces
diff --git a/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp b/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
index 286022ec3e..8df1c4bdbb 100644
--- a/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
+++ b/rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
@@ -25,6 +25,7 @@
 #include "rclcpp/event.hpp"
 #include "rclcpp/exceptions.hpp"
 #include "rclcpp/graph_listener.hpp"
+#include "rclcpp/node_interfaces/node_graph_interface.hpp"
 
 using rclcpp::node_interfaces::NodeGraph;
 using rclcpp::exceptions::throw_from_rcl_error;
@@ -484,3 +485,75 @@ NodeGraph::get_subscriptions_info_by_topic(
     no_mangle,
     rcl_get_subscriptions_info_by_topic);
 }
+
+std::string &
+rclcpp::TopicEndpointInfo::node_name()
+{
+  return node_name_;
+}
+
+const std::string &
+rclcpp::TopicEndpointInfo::node_name() const
+{
+  return node_name_;
+}
+
+std::string &
+rclcpp::TopicEndpointInfo::node_namespace()
+{
+  return node_namespace_;
+}
+
+const std::string &
+rclcpp::TopicEndpointInfo::node_namespace() const
+{
+  return node_namespace_;
+}
+
+std::string &
+rclcpp::TopicEndpointInfo::topic_type()
+{
+  return topic_type_;
+}
+
+const std::string &
+rclcpp::TopicEndpointInfo::topic_type() const
+{
+  return topic_type_;
+}
+
+rclcpp::EndpointType &
+rclcpp::TopicEndpointInfo::endpoint_type()
+{
+  return endpoint_type_;
+}
+
+const rclcpp::EndpointType &
+rclcpp::TopicEndpointInfo::endpoint_type() const
+{
+  return endpoint_type_;
+}
+
+std::array<uint8_t, RMW_GID_STORAGE_SIZE> &
+rclcpp::TopicEndpointInfo::endpoint_gid()
+{
+  return endpoint_gid_;
+}
+
+const std::array<uint8_t, RMW_GID_STORAGE_SIZE> &
+rclcpp::TopicEndpointInfo::endpoint_gid() const
+{
+  return endpoint_gid_;
+}
+
+rclcpp::QoS &
+rclcpp::TopicEndpointInfo::qos_profile()
+{
+  return qos_profile_;
+}
+
+const rclcpp::QoS &
+rclcpp::TopicEndpointInfo::qos_profile() const
+{
+  return qos_profile_;
+}
diff --git a/rclcpp/test/test_node.cpp b/rclcpp/test/test_node.cpp
index e90dedf846..003b3f6e12 100644
--- a/rclcpp/test/test_node.cpp
+++ b/rclcpp/test/test_node.cpp
@@ -2549,11 +2549,11 @@ TEST_F(TestNode, get_publishers_subscriptions_info_by_topic) {
   // Subscription list should be empty
   EXPECT_TRUE(node->get_subscriptions_info_by_topic(fq_topic_name).empty());
   // Verify publisher list has the right data.
-  EXPECT_EQ(node->get_name(), publisher_list[0].node_name);
-  EXPECT_EQ(node->get_namespace(), publisher_list[0].node_namespace);
-  EXPECT_EQ("test_msgs/msg/BasicTypes", publisher_list[0].topic_type);
-  EXPECT_EQ(rclcpp::EndpointType::Publisher, publisher_list[0].endpoint_type);
-  auto actual_qos_profile = publisher_list[0].qos.get_rmw_qos_profile();
+  EXPECT_EQ(node->get_name(), publisher_list[0].node_name());
+  EXPECT_EQ(node->get_namespace(), publisher_list[0].node_namespace());
+  EXPECT_EQ("test_msgs/msg/BasicTypes", publisher_list[0].topic_type());
+  EXPECT_EQ(rclcpp::EndpointType::Publisher, publisher_list[0].endpoint_type());
+  auto actual_qos_profile = publisher_list[0].qos_profile().get_rmw_qos_profile();
 
   auto assert_qos_profile = [](const rmw_qos_profile_t & qos1, const rmw_qos_profile_t & qos2) {
       // Depth and history are skipped because they are not retrieved.
@@ -2604,17 +2604,17 @@ TEST_F(TestNode, get_publishers_subscriptions_info_by_topic) {
   EXPECT_EQ(subscription_list.size(), (size_t)1);
 
   // Verify publisher and subscription list has the right data.
-  EXPECT_EQ(node->get_name(), publisher_list[0].node_name);
-  EXPECT_EQ(node->get_namespace(), publisher_list[0].node_namespace);
-  EXPECT_EQ("test_msgs/msg/BasicTypes", publisher_list[0].topic_type);
-  EXPECT_EQ(rclcpp::EndpointType::Publisher, publisher_list[0].endpoint_type);
-  auto publisher_qos_profile = publisher_list[0].qos.get_rmw_qos_profile();
+  EXPECT_EQ(node->get_name(), publisher_list[0].node_name());
+  EXPECT_EQ(node->get_namespace(), publisher_list[0].node_namespace());
+  EXPECT_EQ("test_msgs/msg/BasicTypes", publisher_list[0].topic_type());
+  EXPECT_EQ(rclcpp::EndpointType::Publisher, publisher_list[0].endpoint_type());
+  auto publisher_qos_profile = publisher_list[0].qos_profile().get_rmw_qos_profile();
   assert_qos_profile(qos.get_rmw_qos_profile(), publisher_qos_profile);
-  EXPECT_EQ(node->get_name(), subscription_list[0].node_name);
-  EXPECT_EQ(node->get_namespace(), subscription_list[0].node_namespace);
-  EXPECT_EQ("test_msgs/msg/BasicTypes", subscription_list[0].topic_type);
-  EXPECT_EQ(rclcpp::EndpointType::Subscription, subscription_list[0].endpoint_type);
-  auto subscription_qos_profile = subscription_list[0].qos.get_rmw_qos_profile();
+  EXPECT_EQ(node->get_name(), subscription_list[0].node_name());
+  EXPECT_EQ(node->get_namespace(), subscription_list[0].node_namespace());
+  EXPECT_EQ("test_msgs/msg/BasicTypes", subscription_list[0].topic_type());
+  EXPECT_EQ(rclcpp::EndpointType::Subscription, subscription_list[0].endpoint_type());
+  auto subscription_qos_profile = subscription_list[0].qos_profile().get_rmw_qos_profile();
   assert_qos_profile(qos2.get_rmw_qos_profile(), subscription_qos_profile);
 
   // Error cases
