Skip to content

Commit 9487121

Browse files
ivanpaunojacobperron
authored andcommitted
Add get subscription names and types by node method to Node class (osrf#35)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
1 parent aa9f8d7 commit 9487121

File tree

5 files changed

+164
-0
lines changed

5 files changed

+164
-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
@@ -146,6 +146,15 @@ JNIEXPORT void
146146
JNICALL Java_org_ros2_rcljava_node_NodeImpl_nativeGetPublisherNamesAndTypesByNode(
147147
JNIEnv *, jclass, jlong, jstring, jstring, jobject);
148148

149+
/*
150+
* Class: org_ros2_rcljava_node_NodeImpl
151+
* Method: nativeGetSubscriptionNamesAndTypesByNode
152+
* Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/util/Collection;)V
153+
*/
154+
JNIEXPORT void
155+
JNICALL Java_org_ros2_rcljava_node_NodeImpl_nativeGetSubscriptionNamesAndTypesByNode(
156+
JNIEnv *, jclass, jlong, jstring, jstring, jobject);
157+
149158
#ifdef __cplusplus
150159
}
151160
#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
@@ -525,3 +525,41 @@ Java_org_ros2_rcljava_node_NodeImpl_nativeGetPublisherNamesAndTypesByNode(
525525
RCLJAVA_COMMON_THROW_FROM_RCL(env, ret, "failed to get publisher names and types");
526526
fill_jnames_and_types(env, publisher_names_and_types, jnames_and_types);
527527
}
528+
529+
JNIEXPORT void JNICALL
530+
Java_org_ros2_rcljava_node_NodeImpl_nativeGetSubscriptionNamesAndTypesByNode(
531+
JNIEnv * env, jclass, jlong handle, jstring jname, jstring jnamespace, jobject jnames_and_types)
532+
{
533+
rcl_node_t * node = reinterpret_cast<rcl_node_t *>(handle);
534+
if (!node) {
535+
rcljava_throw_exception(env, "java/lang/IllegalArgumentException", "node handle is NULL");
536+
return;
537+
}
538+
539+
const char * name = env->GetStringUTFChars(jname, NULL);
540+
auto release_jname = rcpputils::make_scope_exit(
541+
[jname, name, env]() {env->ReleaseStringUTFChars(jname, name);});
542+
const char * namespace_ = env->GetStringUTFChars(jnamespace, NULL);
543+
auto release_jnamespace = rcpputils::make_scope_exit(
544+
[jnamespace, namespace_, env]() {env->ReleaseStringUTFChars(jnamespace, namespace_);});
545+
rcl_allocator_t allocator = rcl_get_default_allocator();
546+
rcl_names_and_types_t subscription_names_and_types = rcl_get_zero_initialized_names_and_types();
547+
auto fini_names_and_types = rcpputils::make_scope_exit(
548+
[pnames_and_types = &subscription_names_and_types, env]() {
549+
rcl_ret_t ret = rcl_names_and_types_fini(pnames_and_types);
550+
if (!env->ExceptionCheck() && RCL_RET_OK != ret) {
551+
rcljava_throw_rclexception(
552+
env, ret, "failed to fini subscription names and types structure");
553+
}
554+
});
555+
556+
rcl_ret_t ret = rcl_get_subscriber_names_and_types_by_node(
557+
node,
558+
&allocator,
559+
false,
560+
name,
561+
namespace_,
562+
&subscription_names_and_types);
563+
RCLJAVA_COMMON_THROW_FROM_RCL(env, ret, "failed to get subscription names and types");
564+
fill_jnames_and_types(env, subscription_names_and_types, jnames_and_types);
565+
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,4 +637,16 @@ <T extends ServiceDefinition> Client<T> createClient(final Class<T> serviceType,
637637
* @return the detected publisher names and types.
638638
*/
639639
Collection<NameAndTypes> getPublisherNamesAndTypesByNode(String nodeName, String nodeNamespace);
640+
641+
/**
642+
* Return the subscription names and types that were created from the node specified by the given
643+
* node name and namespace.
644+
* See @{link graph#NameAndTypes} for more information about the returned value.
645+
*
646+
* @param nodeName name of the node we want to know its subscriptions.
647+
* @param nodeNamespace namespace of the node we want to know its subscriptions.
648+
* @return the detected subscription names and types.
649+
*/
650+
Collection<NameAndTypes> getSubscriptionNamesAndTypesByNode(
651+
String nodeName, String nodeNamespace);
640652
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,4 +842,15 @@ public final Collection<NameAndTypes> getPublisherNamesAndTypesByNode(
842842

843843
private static native final Collection<NameAndTypes> nativeGetPublisherNamesAndTypesByNode(
844844
long handle, String nodeName, String nodeNamespace, Collection<NameAndTypes> namesAndTypes);
845+
846+
public final Collection<NameAndTypes> getSubscriptionNamesAndTypesByNode(
847+
String nodeName, String nodeNamespace)
848+
{
849+
Collection<NameAndTypes> namesAndTypes = new ArrayList();
850+
nativeGetSubscriptionNamesAndTypesByNode(this.handle, nodeName, nodeNamespace, namesAndTypes);
851+
return namesAndTypes;
852+
}
853+
854+
private static native final Collection<NameAndTypes> nativeGetSubscriptionNamesAndTypesByNode(
855+
long handle, String nodeName, String nodeNamespace, Collection<NameAndTypes> namesAndTypes);
845856
}

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

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,4 +1272,98 @@ public void accept(final Collection<NameAndTypes> local, Collection<NameAndTypes
12721272
subscription.dispose();
12731273
remoteNode.dispose();
12741274
}
1275+
1276+
@Test
1277+
public final void testGetSubscriptionNamesAndTypesByNode() throws Exception {
1278+
final Node remoteNode = RCLJava.createNode("test_get_subscription_names_and_types_remote_node");
1279+
Subscription<rcljava.msg.Empty> subscription1 = node.<rcljava.msg.Empty>createSubscription(
1280+
rcljava.msg.Empty.class, "test_get_subscription_names_and_types_one",
1281+
new Consumer<rcljava.msg.Empty>() {
1282+
public void accept(final rcljava.msg.Empty msg) {}
1283+
});
1284+
Subscription<rcljava.msg.Empty> subscription2 = node.<rcljava.msg.Empty>createSubscription(
1285+
rcljava.msg.Empty.class, "test_get_subscription_names_and_types_two",
1286+
new Consumer<rcljava.msg.Empty>() {
1287+
public void accept(final rcljava.msg.Empty msg) {}
1288+
});
1289+
Subscription<rcljava.msg.Empty> subscription3 = remoteNode.<rcljava.msg.Empty>createSubscription(
1290+
rcljava.msg.Empty.class, "test_get_subscription_names_and_types_two",
1291+
new Consumer<rcljava.msg.Empty>() {
1292+
public void accept(final rcljava.msg.Empty msg) {}
1293+
});
1294+
Subscription<rcljava.msg.Empty> subscription4 = remoteNode.<rcljava.msg.Empty>createSubscription(
1295+
rcljava.msg.Empty.class, "test_get_subscription_names_and_types_three",
1296+
new Consumer<rcljava.msg.Empty>() {
1297+
public void accept(final rcljava.msg.Empty msg) {}
1298+
});
1299+
Publisher<rcljava.msg.UInt32> publisher = node.<rcljava.msg.UInt32>createPublisher(
1300+
rcljava.msg.UInt32.class, "test_get_topic_names_and_types_this_should_not_appear");
1301+
1302+
BiConsumer<Collection<NameAndTypes>, Collection<NameAndTypes>> validateNameAndTypes =
1303+
new BiConsumer<Collection<NameAndTypes>, Collection<NameAndTypes>>() {
1304+
public void accept(final Collection<NameAndTypes> local, Collection<NameAndTypes> remote) {
1305+
// TODO(ivanpauno): Using assertj may help a lot here https://assertj.github.io/doc/.
1306+
assertEquals(local.size(), 2);
1307+
assertTrue(
1308+
"topic 'test_get_subscription_names_and_types_one' was not discovered for local node",
1309+
local.contains(
1310+
new NameAndTypes(
1311+
"/test_get_subscription_names_and_types_one",
1312+
new ArrayList(Arrays.asList("rcljava/msg/Empty")))));
1313+
assertTrue(
1314+
"topic 'test_get_subscription_names_and_types_two' was not discovered for local node",
1315+
local.contains(
1316+
new NameAndTypes(
1317+
"/test_get_subscription_names_and_types_two",
1318+
new ArrayList(Arrays.asList("rcljava/msg/Empty")))));
1319+
1320+
assertEquals(remote.size(), 2);
1321+
assertTrue(
1322+
"topic 'test_get_subscription_names_and_types_two' was not discovered for remote node",
1323+
remote.contains(
1324+
new NameAndTypes(
1325+
"/test_get_subscription_names_and_types_two",
1326+
new ArrayList(Arrays.asList("rcljava/msg/Empty")))));
1327+
assertTrue(
1328+
"topic 'test_get_subscription_names_and_types_three' was not discovered for remote node",
1329+
remote.contains(
1330+
new NameAndTypes(
1331+
"/test_get_subscription_names_and_types_three",
1332+
new ArrayList(Arrays.asList("rcljava/msg/Empty")))));
1333+
}
1334+
};
1335+
1336+
long start = System.currentTimeMillis();
1337+
boolean ok = false;
1338+
Collection<NameAndTypes> local = null;
1339+
Collection<NameAndTypes> remote = null;
1340+
do {
1341+
local = this.node.getSubscriptionNamesAndTypesByNode("test_node", "/");
1342+
remote = this.node.getSubscriptionNamesAndTypesByNode(
1343+
"test_get_subscription_names_and_types_remote_node", "/");
1344+
try {
1345+
validateNameAndTypes.accept(local, remote);
1346+
ok = true;
1347+
} catch (AssertionError err) {
1348+
// ignore here, it's going to be validated again at the end.
1349+
}
1350+
// TODO(ivanpauno): We could wait for the graph guard condition to be triggered if that
1351+
// would be available.
1352+
try {
1353+
TimeUnit.MILLISECONDS.sleep(100);
1354+
} catch (InterruptedException err) {
1355+
// ignore
1356+
}
1357+
} while (!ok && System.currentTimeMillis() < start + 1000);
1358+
assertNotNull(local);
1359+
assertNotNull(remote);
1360+
validateNameAndTypes.accept(local, remote);
1361+
1362+
subscription1.dispose();
1363+
subscription2.dispose();
1364+
subscription3.dispose();
1365+
subscription4.dispose();
1366+
publisher.dispose();
1367+
remoteNode.dispose();
1368+
}
12751369
}

0 commit comments

Comments
 (0)