Skip to content

Commit ecd8a84

Browse files
committed
Implement nativeGetServiceNamesAndTypes method (osrf#33)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
1 parent 20cbace commit ecd8a84

File tree

5 files changed

+151
-31
lines changed

5 files changed

+151
-31
lines changed

rcljava/include/org_ros2_rcljava_node_NodeImpl.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,15 @@ JNIEXPORT void
110110
JNICALL Java_org_ros2_rcljava_node_NodeImpl_nativeGetTopicNamesAndTypes(
111111
JNIEnv *, jclass, jlong, jobject);
112112

113+
/*
114+
* Class: org_ros2_rcljava_node_NodeImpl
115+
* Method: nativeGetServiceNamesAndTypes
116+
* Signature: (JLjava/util/Collection;)V
117+
*/
118+
JNIEXPORT void
119+
JNICALL Java_org_ros2_rcljava_node_NodeImpl_nativeGetServiceNamesAndTypes(
120+
JNIEnv *, jclass, jlong, jobject);
121+
113122
/*
114123
* Class: org_ros2_rcljava_node_NodeImpl
115124
* Method: nativeGetPublishersInfo

rcljava/src/main/cpp/org_ros2_rcljava_node_NodeImpl.cpp

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -320,16 +320,10 @@ Java_org_ros2_rcljava_node_NodeImpl_nativeGetNodeNames(
320320
}
321321
}
322322

323-
JNIEXPORT void JNICALL
324-
Java_org_ros2_rcljava_node_NodeImpl_nativeGetTopicNamesAndTypes(
325-
JNIEnv * env, jclass, jlong handle, jobject jnames_and_types)
323+
void
324+
fill_jnames_and_types(
325+
JNIEnv * env, const rcl_names_and_types_t & names_and_types, jobject jnames_and_types)
326326
{
327-
rcl_node_t * node = reinterpret_cast<rcl_node_t *>(handle);
328-
if (!node) {
329-
rcljava_throw_exception(env, "java/lang/IllegalArgumentException", "node handle is NULL");
330-
return;
331-
}
332-
333327
jclass collection_clazz = env->FindClass("java/util/Collection");
334328
jmethodID collection_add_mid = env->GetMethodID(
335329
collection_clazz, "add", "(Ljava/lang/Object;)Z");
@@ -343,34 +337,16 @@ Java_org_ros2_rcljava_node_NodeImpl_nativeGetTopicNamesAndTypes(
343337
jfieldID types_fid = env->GetFieldID(name_and_types_clazz, "types", "Ljava/util/Collection;");
344338
RCLJAVA_COMMON_CHECK_FOR_EXCEPTION(env);
345339

346-
rcl_allocator_t allocator = rcl_get_default_allocator();
347-
rcl_names_and_types_t topic_names_and_types = rcl_get_zero_initialized_names_and_types();
348-
349-
rcl_ret_t ret = rcl_get_topic_names_and_types(
350-
node,
351-
&allocator,
352-
false,
353-
&topic_names_and_types);
354-
RCLJAVA_COMMON_THROW_FROM_RCL(env, ret, "failed to get topic names and types");
355-
auto cleanup_names_and_types = rcpputils::make_scope_exit(
356-
[pnames_and_types = &topic_names_and_types, env]() {
357-
rcl_ret_t ret = rcl_names_and_types_fini(pnames_and_types);
358-
if (!env->ExceptionCheck() && RCL_RET_OK != ret) {
359-
rcljava_throw_rclexception(env, ret, "failed to fini topic names and types structure");
360-
}
361-
}
362-
);
363-
364-
for (size_t i = 0; i < topic_names_and_types.names.size; i++) {
340+
for (size_t i = 0; i < names_and_types.names.size; i++) {
365341
jobject jitem = env->NewObject(name_and_types_clazz, name_and_types_init_mid);
366342
RCLJAVA_COMMON_CHECK_FOR_EXCEPTION(env);
367-
jstring jname = env->NewStringUTF(topic_names_and_types.names.data[i]);
343+
jstring jname = env->NewStringUTF(names_and_types.names.data[i]);
368344
RCLJAVA_COMMON_CHECK_FOR_EXCEPTION(env);
369345
env->SetObjectField(jitem, name_fid, jname);
370346
// the default constructor already inits types to an empty ArrayList
371347
jobject jtypes = env->GetObjectField(jitem, types_fid);
372-
for (size_t j = 0; j < topic_names_and_types.types[i].size; j++) {
373-
jstring jtype = env->NewStringUTF(topic_names_and_types.types[i].data[j]);
348+
for (size_t j = 0; j < names_and_types.types[i].size; j++) {
349+
jstring jtype = env->NewStringUTF(names_and_types.types[i].data[j]);
374350
env->CallBooleanMethod(jtypes, collection_add_mid, jtype);
375351
RCLJAVA_COMMON_CHECK_FOR_EXCEPTION(env);
376352
}
@@ -379,6 +355,59 @@ Java_org_ros2_rcljava_node_NodeImpl_nativeGetTopicNamesAndTypes(
379355
}
380356
}
381357

358+
JNIEXPORT void JNICALL
359+
Java_org_ros2_rcljava_node_NodeImpl_nativeGetTopicNamesAndTypes(
360+
JNIEnv * env, jclass, jlong handle, jobject jnames_and_types)
361+
{
362+
rcl_node_t * node = reinterpret_cast<rcl_node_t *>(handle);
363+
if (!node) {
364+
rcljava_throw_exception(env, "java/lang/IllegalArgumentException", "node handle is NULL");
365+
return;
366+
}
367+
368+
rcl_allocator_t allocator = rcl_get_default_allocator();
369+
rcl_names_and_types_t topic_names_and_types = rcl_get_zero_initialized_names_and_types();
370+
371+
rcl_ret_t ret = rcl_get_topic_names_and_types(
372+
node,
373+
&allocator,
374+
false,
375+
&topic_names_and_types);
376+
RCLJAVA_COMMON_THROW_FROM_RCL(env, ret, "failed to get topic names and types");
377+
fill_jnames_and_types(env, topic_names_and_types, jnames_and_types);
378+
379+
ret = rcl_names_and_types_fini(&topic_names_and_types);
380+
if (!env->ExceptionCheck() && RCL_RET_OK != ret) {
381+
rcljava_throw_rclexception(env, ret, "failed to fini topic names and types structure");
382+
}
383+
}
384+
385+
JNIEXPORT void JNICALL
386+
Java_org_ros2_rcljava_node_NodeImpl_nativeGetServiceNamesAndTypes(
387+
JNIEnv * env, jclass, jlong handle, jobject jnames_and_types)
388+
{
389+
rcl_node_t * node = reinterpret_cast<rcl_node_t *>(handle);
390+
if (!node) {
391+
rcljava_throw_exception(env, "java/lang/IllegalArgumentException", "node handle is NULL");
392+
return;
393+
}
394+
395+
rcl_allocator_t allocator = rcl_get_default_allocator();
396+
rcl_names_and_types_t service_names_and_types = rcl_get_zero_initialized_names_and_types();
397+
398+
rcl_ret_t ret = rcl_get_service_names_and_types(
399+
node,
400+
&allocator,
401+
&service_names_and_types);
402+
RCLJAVA_COMMON_THROW_FROM_RCL(env, ret, "failed to get service names and types");
403+
fill_jnames_and_types(env, service_names_and_types, jnames_and_types);
404+
405+
ret = rcl_names_and_types_fini(&service_names_and_types);
406+
if (!env->ExceptionCheck() && RCL_RET_OK != ret) {
407+
rcljava_throw_rclexception(env, ret, "failed to fini service names and types structure");
408+
}
409+
}
410+
382411
template<typename FunctorT>
383412
void
384413
get_endpoint_info_common(

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,14 @@ <T extends ServiceDefinition> Client<T> createClient(final Class<T> serviceType,
567567
*/
568568
Collection<NameAndTypes> getTopicNamesAndTypes();
569569

570+
/**
571+
* Return the service names and types that were detected in the graph.
572+
* See @{link graph#NameAndTypes} for more information about the returned value.
573+
*
574+
* @return the detected service names and types.
575+
*/
576+
Collection<NameAndTypes> getServiceNamesAndTypes();
577+
570578
/**
571579
* Get information of all publishers in a topic.
572580
*

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,15 @@ public final Collection<NameAndTypes> getTopicNamesAndTypes() {
778778
private static native final void nativeGetTopicNamesAndTypes(
779779
long handle, Collection<NameAndTypes> namesAndTypes);
780780

781+
public final Collection<NameAndTypes> getServiceNamesAndTypes() {
782+
Collection<NameAndTypes> namesAndTypes = new ArrayList();
783+
nativeGetServiceNamesAndTypes(this.handle, namesAndTypes);
784+
return namesAndTypes;
785+
}
786+
787+
private static native final void nativeGetServiceNamesAndTypes(
788+
long handle, Collection<NameAndTypes> namesAndTypes);
789+
781790
public final Collection<EndpointInfo> getPublishersInfo(final String topicName) {
782791
ArrayList<EndpointInfo> returnValue = new ArrayList();
783792
nativeGetPublishersInfo(this.handle, topicName, returnValue);

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

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@
3939
import java.util.concurrent.TimeUnit;
4040

4141
import org.ros2.rcljava.RCLJava;
42+
import org.ros2.rcljava.client.Client;
4243
import org.ros2.rcljava.concurrent.RCLFuture;
4344
import org.ros2.rcljava.consumers.Consumer;
45+
import org.ros2.rcljava.consumers.TriConsumer;
4446
import org.ros2.rcljava.executors.Executor;
4547
import org.ros2.rcljava.executors.MultiThreadedExecutor;
4648
import org.ros2.rcljava.executors.SingleThreadedExecutor;
@@ -51,6 +53,8 @@
5153
import org.ros2.rcljava.publisher.Publisher;
5254
import org.ros2.rcljava.qos.policies.Reliability;
5355
import org.ros2.rcljava.qos.QoSProfile;
56+
import org.ros2.rcljava.service.RMWRequestId;
57+
import org.ros2.rcljava.service.Service;
5458
import org.ros2.rcljava.subscription.Subscription;
5559

5660
public class NodeTest {
@@ -1011,6 +1015,67 @@ public void accept(final Collection<NameAndTypes> namesAndTypes) {
10111015
subscription2.dispose();
10121016
}
10131017

1018+
@Test
1019+
public final void testGetServiceNamesAndTypes() throws Exception {
1020+
Service<rcljava.srv.AddTwoInts> service = node.<rcljava.srv.AddTwoInts>createService(
1021+
rcljava.srv.AddTwoInts.class, "test_service_names_and_types_one",
1022+
new TriConsumer<
1023+
RMWRequestId, rcljava.srv.AddTwoInts_Request, rcljava.srv.AddTwoInts_Response>()
1024+
{
1025+
public final void accept(
1026+
final RMWRequestId header,
1027+
final rcljava.srv.AddTwoInts_Request request,
1028+
final rcljava.srv.AddTwoInts_Response response)
1029+
{}
1030+
});
1031+
Client<rcljava.srv.AddTwoInts> client = node.<rcljava.srv.AddTwoInts>createClient(
1032+
rcljava.srv.AddTwoInts.class, "test_service_names_and_types_two");
1033+
1034+
Consumer<Collection<NameAndTypes>> validateNameAndTypes =
1035+
new Consumer<Collection<NameAndTypes>>() {
1036+
public void accept(final Collection<NameAndTypes> namesAndTypes) {
1037+
assertEquals(namesAndTypes.size(), 2);
1038+
assertTrue(
1039+
"service 'test_service_names_and_types_one' was not discovered",
1040+
namesAndTypes.contains(
1041+
new NameAndTypes(
1042+
"/test_service_names_and_types_one",
1043+
new ArrayList(Arrays.asList("rcljava/srv/AddTwoInts")))));
1044+
assertTrue(
1045+
"service 'test_service_names_and_types_two' was not discovered",
1046+
namesAndTypes.contains(
1047+
new NameAndTypes(
1048+
"/test_service_names_and_types_two",
1049+
new ArrayList(Arrays.asList("rcljava/srv/AddTwoInts")))));
1050+
}
1051+
};
1052+
1053+
long start = System.currentTimeMillis();
1054+
boolean ok = false;
1055+
Collection<NameAndTypes> namesAndTypes = null;
1056+
do {
1057+
namesAndTypes = this.node.getServiceNamesAndTypes();
1058+
try {
1059+
validateNameAndTypes.accept(namesAndTypes);
1060+
ok = true;
1061+
} catch (AssertionError err) {
1062+
// ignore here, it's going to be validated again at the end.
1063+
}
1064+
// TODO(ivanpauno): We could wait for the graph guard condition to be triggered if that
1065+
// would be available.
1066+
try {
1067+
TimeUnit.MILLISECONDS.sleep(100);
1068+
} catch (InterruptedException err) {
1069+
// ignore
1070+
}
1071+
} while (!ok && System.currentTimeMillis() < start + 1000);
1072+
assertNotNull(namesAndTypes);
1073+
validateNameAndTypes.accept(namesAndTypes);
1074+
1075+
service.dispose();
1076+
client.dispose();
1077+
}
1078+
10141079
@Test
10151080
public final void testGetPublishersInfo() {
10161081
Publisher<rcljava.msg.UInt32> publisher =

0 commit comments

Comments
 (0)