Skip to content

Commit 43e9d32

Browse files
ivanpaunojacobperron
authored andcommitted
Add getServiceNamesAndTypes method to Node class (osrf#36)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
1 parent 9487121 commit 43e9d32

File tree

5 files changed

+186
-0
lines changed

5 files changed

+186
-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
@@ -155,6 +155,15 @@ JNIEXPORT void
155155
JNICALL Java_org_ros2_rcljava_node_NodeImpl_nativeGetSubscriptionNamesAndTypesByNode(
156156
JNIEnv *, jclass, jlong, jstring, jstring, jobject);
157157

158+
/*
159+
* Class: org_ros2_rcljava_node_NodeImpl
160+
* Method: nativeServiceNamesAndTypesByNode
161+
* Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/util/Collection;)V
162+
*/
163+
JNIEXPORT void
164+
JNICALL Java_org_ros2_rcljava_node_NodeImpl_nativeGetServiceNamesAndTypesByNode(
165+
JNIEnv *, jclass, jlong, jstring, jstring, jobject);
166+
158167
#ifdef __cplusplus
159168
}
160169
#endif

rcljava/src/main/cpp/org_ros2_rcljava_node_NodeImpl.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,3 +563,39 @@ Java_org_ros2_rcljava_node_NodeImpl_nativeGetSubscriptionNamesAndTypesByNode(
563563
RCLJAVA_COMMON_THROW_FROM_RCL(env, ret, "failed to get subscription names and types");
564564
fill_jnames_and_types(env, subscription_names_and_types, jnames_and_types);
565565
}
566+
567+
JNIEXPORT void JNICALL Java_org_ros2_rcljava_node_NodeImpl_nativeGetServiceNamesAndTypesByNode(
568+
JNIEnv * env, jclass, jlong handle, jstring jname, jstring jnamespace, jobject jnames_and_types)
569+
{
570+
rcl_node_t * node = reinterpret_cast<rcl_node_t *>(handle);
571+
if (!node) {
572+
rcljava_throw_exception(env, "java/lang/IllegalArgumentException", "node handle is NULL");
573+
return;
574+
}
575+
576+
const char * name = env->GetStringUTFChars(jname, NULL);
577+
auto release_jname = rcpputils::make_scope_exit(
578+
[jname, name, env]() {env->ReleaseStringUTFChars(jname, name);});
579+
const char * namespace_ = env->GetStringUTFChars(jnamespace, NULL);
580+
auto release_jnamespace = rcpputils::make_scope_exit(
581+
[jnamespace, namespace_, env]() {env->ReleaseStringUTFChars(jnamespace, namespace_);});
582+
rcl_allocator_t allocator = rcl_get_default_allocator();
583+
rcl_names_and_types_t service_names_and_types = rcl_get_zero_initialized_names_and_types();
584+
auto fini_names_and_types = rcpputils::make_scope_exit(
585+
[pnames_and_types = &service_names_and_types, env]() {
586+
rcl_ret_t ret = rcl_names_and_types_fini(pnames_and_types);
587+
if (!env->ExceptionCheck() && RCL_RET_OK != ret) {
588+
rcljava_throw_rclexception(
589+
env, ret, "failed to fini service names and types structure");
590+
}
591+
});
592+
593+
rcl_ret_t ret = rcl_get_service_names_and_types_by_node(
594+
node,
595+
&allocator,
596+
name,
597+
namespace_,
598+
&service_names_and_types);
599+
RCLJAVA_COMMON_THROW_FROM_RCL(env, ret, "failed to get service names and types");
600+
fill_jnames_and_types(env, service_names_and_types, jnames_and_types);
601+
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,4 +649,16 @@ <T extends ServiceDefinition> Client<T> createClient(final Class<T> serviceType,
649649
*/
650650
Collection<NameAndTypes> getSubscriptionNamesAndTypesByNode(
651651
String nodeName, String nodeNamespace);
652+
653+
/**
654+
* Return the service server names and types that were created from the node specified by the
655+
* given node name and namespace.
656+
* See @{link graph#NameAndTypes} for more information about the returned value.
657+
*
658+
* @param nodeName name of the node we want to know its services.
659+
* @param nodeNamespace namespace of the node we want to know its services.
660+
* @return the detected service server names and types.
661+
*/
662+
Collection<NameAndTypes> getServiceNamesAndTypesByNode(
663+
String nodeName, String nodeNamespace);
652664
}

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

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

854854
private static native final Collection<NameAndTypes> nativeGetSubscriptionNamesAndTypesByNode(
855855
long handle, String nodeName, String nodeNamespace, Collection<NameAndTypes> namesAndTypes);
856+
857+
public final Collection<NameAndTypes> getServiceNamesAndTypesByNode(
858+
String nodeName, String nodeNamespace)
859+
{
860+
Collection<NameAndTypes> namesAndTypes = new ArrayList();
861+
nativeGetServiceNamesAndTypesByNode(this.handle, nodeName, nodeNamespace, namesAndTypes);
862+
return namesAndTypes;
863+
}
864+
865+
private static native final Collection<NameAndTypes> nativeGetServiceNamesAndTypesByNode(
866+
long handle, String nodeName, String nodeNamespace, Collection<NameAndTypes> namesAndTypes);
856867
}

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

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,4 +1366,122 @@ public void accept(final Collection<NameAndTypes> local, Collection<NameAndTypes
13661366
publisher.dispose();
13671367
remoteNode.dispose();
13681368
}
1369+
1370+
@Test
1371+
public final void testGetServiceNamesAndTypesByNode() throws Exception {
1372+
final Node remoteNode = RCLJava.createNode("test_get_service_names_and_types_remote_node");
1373+
Service<rcljava.srv.AddTwoInts> service1 = node.<rcljava.srv.AddTwoInts>createService(
1374+
rcljava.srv.AddTwoInts.class, "test_get_service_names_and_types_one",
1375+
new TriConsumer<
1376+
RMWRequestId, rcljava.srv.AddTwoInts_Request, rcljava.srv.AddTwoInts_Response>()
1377+
{
1378+
public final void accept(
1379+
final RMWRequestId header,
1380+
final rcljava.srv.AddTwoInts_Request request,
1381+
final rcljava.srv.AddTwoInts_Response response)
1382+
{}
1383+
});
1384+
Service<rcljava.srv.AddTwoInts> service2 = node.<rcljava.srv.AddTwoInts>createService(
1385+
rcljava.srv.AddTwoInts.class, "test_get_service_names_and_types_two",
1386+
new TriConsumer<
1387+
RMWRequestId, rcljava.srv.AddTwoInts_Request, rcljava.srv.AddTwoInts_Response>()
1388+
{
1389+
public final void accept(
1390+
final RMWRequestId header,
1391+
final rcljava.srv.AddTwoInts_Request request,
1392+
final rcljava.srv.AddTwoInts_Response response)
1393+
{}
1394+
});
1395+
Service<rcljava.srv.AddTwoInts> service3 = remoteNode.<rcljava.srv.AddTwoInts>createService(
1396+
rcljava.srv.AddTwoInts.class, "test_get_service_names_and_types_two",
1397+
new TriConsumer<
1398+
RMWRequestId, rcljava.srv.AddTwoInts_Request, rcljava.srv.AddTwoInts_Response>()
1399+
{
1400+
public final void accept(
1401+
final RMWRequestId header,
1402+
final rcljava.srv.AddTwoInts_Request request,
1403+
final rcljava.srv.AddTwoInts_Response response)
1404+
{}
1405+
});
1406+
Service<rcljava.srv.AddTwoInts> service4 = remoteNode.<rcljava.srv.AddTwoInts>createService(
1407+
rcljava.srv.AddTwoInts.class, "test_get_service_names_and_types_three",
1408+
new TriConsumer<
1409+
RMWRequestId, rcljava.srv.AddTwoInts_Request, rcljava.srv.AddTwoInts_Response>()
1410+
{
1411+
public final void accept(
1412+
final RMWRequestId header,
1413+
final rcljava.srv.AddTwoInts_Request request,
1414+
final rcljava.srv.AddTwoInts_Response response)
1415+
{}
1416+
});
1417+
Client<rcljava.srv.AddTwoInts> client = node.<rcljava.srv.AddTwoInts>createClient(
1418+
rcljava.srv.AddTwoInts.class, "test_get_service_names_and_types_this_should_not_appear");
1419+
1420+
BiConsumer<Collection<NameAndTypes>, Collection<NameAndTypes>> validateNameAndTypes =
1421+
new BiConsumer<Collection<NameAndTypes>, Collection<NameAndTypes>>() {
1422+
public void accept(final Collection<NameAndTypes> local, Collection<NameAndTypes> remote) {
1423+
// TODO(ivanpauno): Using assertj may help a lot here https://assertj.github.io/doc/.
1424+
assertEquals(local.size(), 2);
1425+
assertTrue(
1426+
"service 'test_get_service_names_and_types_one' was not discovered for local node",
1427+
local.contains(
1428+
new NameAndTypes(
1429+
"/test_get_service_names_and_types_one",
1430+
new ArrayList(Arrays.asList("rcljava/srv/AddTwoInts")))));
1431+
assertTrue(
1432+
"service 'test_get_service_names_and_types_two' was not discovered for local node",
1433+
local.contains(
1434+
new NameAndTypes(
1435+
"/test_get_service_names_and_types_two",
1436+
new ArrayList(Arrays.asList("rcljava/srv/AddTwoInts")))));
1437+
1438+
assertEquals(remote.size(), 2);
1439+
assertTrue(
1440+
"service 'test_get_service_names_and_types_two' was not discovered for remote node",
1441+
remote.contains(
1442+
new NameAndTypes(
1443+
"/test_get_service_names_and_types_two",
1444+
new ArrayList(Arrays.asList("rcljava/srv/AddTwoInts")))));
1445+
assertTrue(
1446+
"service 'test_get_service_names_and_types_three' was not discovered for remote node",
1447+
remote.contains(
1448+
new NameAndTypes(
1449+
"/test_get_service_names_and_types_three",
1450+
new ArrayList(Arrays.asList("rcljava/srv/AddTwoInts")))));
1451+
}
1452+
};
1453+
1454+
long start = System.currentTimeMillis();
1455+
boolean ok = false;
1456+
Collection<NameAndTypes> local = null;
1457+
Collection<NameAndTypes> remote = null;
1458+
do {
1459+
local = this.node.getServiceNamesAndTypesByNode("test_node", "/");
1460+
remote = this.node.getServiceNamesAndTypesByNode(
1461+
"test_get_service_names_and_types_remote_node", "/");
1462+
try {
1463+
validateNameAndTypes.accept(local, remote);
1464+
ok = true;
1465+
} catch (AssertionError err) {
1466+
// ignore here, it's going to be validated again at the end.
1467+
}
1468+
// TODO(ivanpauno): We could wait for the graph guard condition to be triggered if that
1469+
// would be available.
1470+
try {
1471+
TimeUnit.MILLISECONDS.sleep(100);
1472+
} catch (InterruptedException err) {
1473+
// ignore
1474+
}
1475+
} while (!ok && System.currentTimeMillis() < start + 1000);
1476+
assertNotNull(local);
1477+
assertNotNull(remote);
1478+
validateNameAndTypes.accept(local, remote);
1479+
1480+
service1.dispose();
1481+
service2.dispose();
1482+
service3.dispose();
1483+
service4.dispose();
1484+
client.dispose();
1485+
remoteNode.dispose();
1486+
}
13691487
}

0 commit comments

Comments
 (0)