Skip to content

Commit 60ac293

Browse files
ivanpaunojacobperron
authored andcommitted
Add get publishers by node (osrf#34)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
1 parent a938544 commit 60ac293

File tree

5 files changed

+155
-0
lines changed

5 files changed

+155
-0
lines changed

rcljava/include/org_ros2_rcljava_node_NodeImpl.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,15 @@ JNIEXPORT void
137137
JNICALL Java_org_ros2_rcljava_node_NodeImpl_nativeGetSubscriptionsInfo(
138138
JNIEnv *, jclass, jlong, jstring, jobject);
139139

140+
/*
141+
* Class: org_ros2_rcljava_node_NodeImpl
142+
* Method: nativeGetPublisherNamesAndTypesByNode
143+
* Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/util/Collection;)V
144+
*/
145+
JNIEXPORT void
146+
JNICALL Java_org_ros2_rcljava_node_NodeImpl_nativeGetPublisherNamesAndTypesByNode(
147+
JNIEnv *, jclass, jlong, jstring, jstring, jobject);
148+
140149
#ifdef __cplusplus
141150
}
142151
#endif

rcljava/src/main/cpp/org_ros2_rcljava_node_NodeImpl.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,3 +487,41 @@ Java_org_ros2_rcljava_node_NodeImpl_nativeGetSubscriptionsInfo(
487487
get_endpoint_info_common(
488488
env, handle, jtopic_name, jsubscriptions_info, rcl_get_subscriptions_info_by_topic);
489489
}
490+
491+
JNIEXPORT void JNICALL
492+
Java_org_ros2_rcljava_node_NodeImpl_nativeGetPublisherNamesAndTypesByNode(
493+
JNIEnv * env, jclass, jlong handle, jstring jname, jstring jnamespace, jobject jnames_and_types)
494+
{
495+
rcl_node_t * node = reinterpret_cast<rcl_node_t *>(handle);
496+
if (!node) {
497+
rcljava_throw_exception(env, "java/lang/IllegalArgumentException", "node handle is NULL");
498+
return;
499+
}
500+
501+
const char * name = env->GetStringUTFChars(jname, NULL);
502+
auto release_jname = rcpputils::make_scope_exit(
503+
[jname, name, env]() {env->ReleaseStringUTFChars(jname, name);});
504+
const char * namespace_ = env->GetStringUTFChars(jnamespace, NULL);
505+
auto release_jnamespace = rcpputils::make_scope_exit(
506+
[jnamespace, namespace_, env]() {env->ReleaseStringUTFChars(jnamespace, namespace_);});
507+
508+
rcl_allocator_t allocator = rcl_get_default_allocator();
509+
rcl_names_and_types_t publisher_names_and_types = rcl_get_zero_initialized_names_and_types();
510+
auto fini_names_and_types = rcpputils::make_scope_exit(
511+
[pnames_and_types = &publisher_names_and_types, env]() {
512+
rcl_ret_t ret = rcl_names_and_types_fini(pnames_and_types);
513+
if (!env->ExceptionCheck() && RCL_RET_OK != ret) {
514+
rcljava_throw_rclexception(env, ret, "failed to fini publisher names and types structure");
515+
}
516+
});
517+
518+
rcl_ret_t ret = rcl_get_publisher_names_and_types_by_node(
519+
node,
520+
&allocator,
521+
false,
522+
name,
523+
namespace_,
524+
&publisher_names_and_types);
525+
RCLJAVA_COMMON_THROW_FROM_RCL(env, ret, "failed to get publisher names and types");
526+
fill_jnames_and_types(env, publisher_names_and_types, jnames_and_types);
527+
}

rcljava/src/main/java/org/ros2/rcljava/node/Node.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,4 +598,15 @@ <T extends ServiceDefinition> Client<T> createClient(final Class<T> serviceType,
598598
* passed topic.
599599
*/
600600
Collection<EndpointInfo> getSubscriptionsInfo(final String topicName);
601+
602+
/**
603+
* Return the publisher names and types that were created from the node specified by the given
604+
* node name and namespace.
605+
* See @{link graph#NameAndTypes} for more information about the returned value.
606+
*
607+
* @param nodeName name of the node we want to know its publishers.
608+
* @param nodeNamespace namespace of the node we want to know its publishers.
609+
* @return the detected publisher names and types.
610+
*/
611+
Collection<NameAndTypes> getPublisherNamesAndTypesByNode(String nodeName, String nodeNamespace);
601612
}

rcljava/src/main/java/org/ros2/rcljava/node/NodeImpl.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,4 +800,15 @@ public final Collection<EndpointInfo> getSubscriptionsInfo(final String topicNam
800800

801801
private native static final void nativeGetSubscriptionsInfo(
802802
final long handle, final String topicName, ArrayList<EndpointInfo> endpointInfo);
803+
804+
public final Collection<NameAndTypes> getPublisherNamesAndTypesByNode(
805+
String nodeName, String nodeNamespace)
806+
{
807+
Collection<NameAndTypes> namesAndTypes = new ArrayList();
808+
nativeGetPublisherNamesAndTypesByNode(this.handle, nodeName, nodeNamespace, namesAndTypes);
809+
return namesAndTypes;
810+
}
811+
812+
private static native final Collection<NameAndTypes> nativeGetPublisherNamesAndTypesByNode(
813+
long handle, String nodeName, String nodeNamespace, Collection<NameAndTypes> namesAndTypes);
803814
}

rcljava/src/test/java/org/ros2/rcljava/node/NodeTest.java

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.ros2.rcljava.client.Client;
4343
import org.ros2.rcljava.concurrent.RCLFuture;
4444
import org.ros2.rcljava.consumers.Consumer;
45+
import org.ros2.rcljava.consumers.BiConsumer;
4546
import org.ros2.rcljava.consumers.TriConsumer;
4647
import org.ros2.rcljava.executors.Executor;
4748
import org.ros2.rcljava.executors.MultiThreadedExecutor;
@@ -1186,4 +1187,89 @@ public void accept(final Collection<EndpointInfo> info) {
11861187
subscription.dispose();
11871188
subscription2.dispose();
11881189
}
1190+
1191+
@Test
1192+
public final void testGetPublisherNamesAndTypesByNode() throws Exception {
1193+
final Node remoteNode = RCLJava.createNode("test_get_publisher_names_and_types_remote_node");
1194+
Publisher<rcljava.msg.UInt32> publisher1 = node.<rcljava.msg.UInt32>createPublisher(
1195+
rcljava.msg.UInt32.class, "test_get_publisher_names_and_types_one");
1196+
Publisher<rcljava.msg.UInt32> publisher2 = node.<rcljava.msg.UInt32>createPublisher(
1197+
rcljava.msg.UInt32.class, "test_get_publisher_names_and_types_two");
1198+
Publisher<rcljava.msg.UInt32> publisher3 = remoteNode.<rcljava.msg.UInt32>createPublisher(
1199+
rcljava.msg.UInt32.class, "test_get_publisher_names_and_types_two");
1200+
Publisher<rcljava.msg.UInt32> publisher4 = remoteNode.<rcljava.msg.UInt32>createPublisher(
1201+
rcljava.msg.UInt32.class, "test_get_publisher_names_and_types_three");
1202+
Subscription<rcljava.msg.Empty> subscription = node.<rcljava.msg.Empty>createSubscription(
1203+
rcljava.msg.Empty.class, "test_get_topic_names_and_types_this_should_not_appear",
1204+
new Consumer<rcljava.msg.Empty>() {
1205+
public void accept(final rcljava.msg.Empty msg) {}
1206+
});
1207+
1208+
BiConsumer<Collection<NameAndTypes>, Collection<NameAndTypes>> validateNameAndTypes =
1209+
new BiConsumer<Collection<NameAndTypes>, Collection<NameAndTypes>>() {
1210+
public void accept(final Collection<NameAndTypes> local, Collection<NameAndTypes> remote) {
1211+
// TODO(ivanpauno): Using assertj may help a lot here https://assertj.github.io/doc/.
1212+
assertEquals(local.size(), 2);
1213+
assertTrue(
1214+
"topic 'test_get_publisher_names_and_types_one' was not discovered for local node",
1215+
local.contains(
1216+
new NameAndTypes(
1217+
"/test_get_publisher_names_and_types_one",
1218+
new ArrayList(Arrays.asList("rcljava/msg/UInt32")))));
1219+
assertTrue(
1220+
"topic 'test_get_publisher_names_and_types_two' was not discovered for local node",
1221+
local.contains(
1222+
new NameAndTypes(
1223+
"/test_get_publisher_names_and_types_two",
1224+
new ArrayList(Arrays.asList("rcljava/msg/UInt32")))));
1225+
1226+
assertEquals(remote.size(), 2);
1227+
assertTrue(
1228+
"topic 'test_get_publisher_names_and_types_two' was not discovered for remote node",
1229+
remote.contains(
1230+
new NameAndTypes(
1231+
"/test_get_publisher_names_and_types_two",
1232+
new ArrayList(Arrays.asList("rcljava/msg/UInt32")))));
1233+
assertTrue(
1234+
"topic 'test_get_publisher_names_and_types_three' was not discovered for remote node",
1235+
remote.contains(
1236+
new NameAndTypes(
1237+
"/test_get_publisher_names_and_types_three",
1238+
new ArrayList(Arrays.asList("rcljava/msg/UInt32")))));
1239+
}
1240+
};
1241+
1242+
long start = System.currentTimeMillis();
1243+
boolean ok = false;
1244+
Collection<NameAndTypes> local = null;
1245+
Collection<NameAndTypes> remote = null;
1246+
do {
1247+
local = this.node.getPublisherNamesAndTypesByNode("test_node", "/");
1248+
remote = this.node.getPublisherNamesAndTypesByNode(
1249+
"test_get_publisher_names_and_types_remote_node", "/");
1250+
try {
1251+
validateNameAndTypes.accept(local, remote);
1252+
ok = true;
1253+
} catch (AssertionError err) {
1254+
// ignore here, it's going to be validated again at the end.
1255+
}
1256+
// TODO(ivanpauno): We could wait for the graph guard condition to be triggered if that
1257+
// would be available.
1258+
try {
1259+
TimeUnit.MILLISECONDS.sleep(100);
1260+
} catch (InterruptedException err) {
1261+
// ignore
1262+
}
1263+
} while (!ok && System.currentTimeMillis() < start + 1000);
1264+
assertNotNull(local);
1265+
assertNotNull(remote);
1266+
validateNameAndTypes.accept(local, remote);
1267+
1268+
publisher1.dispose();
1269+
publisher2.dispose();
1270+
publisher3.dispose();
1271+
publisher4.dispose();
1272+
subscription.dispose();
1273+
remoteNode.dispose();
1274+
}
11891275
}

0 commit comments

Comments
 (0)