1414
1515#include < jni.h>
1616
17+ #include < limits>
1718#include < string>
19+ #include < sstream>
1820
1921#include " rcl/context.h"
2022#include " rcl/error_handling.h"
2527
2628#include " org_ros2_rcljava_contexts_ContextImpl.h"
2729
30+ using rcljava_common::exceptions::rcljava_throw_exception;
2831using rcljava_common::exceptions::rcljava_throw_rclexception;
2932
3033JNIEXPORT jboolean JNICALL
@@ -36,7 +39,8 @@ Java_org_ros2_rcljava_contexts_ContextImpl_nativeIsValid(JNIEnv *, jclass, jlong
3639}
3740
3841JNIEXPORT void JNICALL
39- Java_org_ros2_rcljava_contexts_ContextImpl_nativeInit (JNIEnv * env, jclass, jlong context_handle)
42+ Java_org_ros2_rcljava_contexts_ContextImpl_nativeInit (
43+ JNIEnv * env, jclass, jlong context_handle, jobjectArray jargs)
4044{
4145 // TODO(jacobperron): Encapsulate init options into a Java class
4246 rcl_init_options_t init_options = rcl_get_zero_initialized_init_options ();
@@ -49,8 +53,42 @@ Java_org_ros2_rcljava_contexts_ContextImpl_nativeInit(JNIEnv * env, jclass, jlon
4953 }
5054
5155 rcl_context_t * context = reinterpret_cast <rcl_context_t *>(context_handle);
52- // TODO(esteve): parse args
53- ret = rcl_init (0 , nullptr , &init_options, context);
56+
57+ // jsize should always fit in a size_t, so the following cast is safe.
58+ const auto argc = static_cast <size_t >(env->GetArrayLength (jargs));
59+ // rcl_init takes an int, check for overflow just in case
60+ if (argc > static_cast <size_t >(std::numeric_limits<int >::max ())) {
61+ std::ostringstream oss (
62+ " args length is longer than expected, maximum length is " , std::ios_base::ate);
63+ oss << std::numeric_limits<int >::max ();
64+ rcljava_throw_exception (
65+ env, " java/lang/IllegalArgumentException" , oss.str ().c_str ());
66+ return ;
67+ }
68+ const char ** argv = nullptr ;
69+ if (argc) {
70+ argv = static_cast <const char **>(malloc (argc * sizeof (char *)));
71+ for (size_t i = 0 ; i < argc; ++i) {
72+ auto item = static_cast <jstring>(env->GetObjectArrayElement (jargs, i));
73+ // an exception here should never happen,
74+ // as the only possible exception is array out of bounds
75+ RCLJAVA_COMMON_CHECK_FOR_EXCEPTION (env);
76+ argv[i] = env->GetStringUTFChars (item, NULL );
77+ }
78+ }
79+
80+ ret = rcl_init (static_cast <int >(argc), argv, &init_options, context);
81+ if (argc) {
82+ for (size_t i = 0 ; i < argc; ++i) {
83+ auto item = static_cast <jstring>(env->GetObjectArrayElement (jargs, i));
84+ // an exception here should never happen,
85+ // as the only possible exception is array out of bounds
86+ RCLJAVA_COMMON_CHECK_FOR_EXCEPTION (env);
87+ env->ReleaseStringUTFChars (item, argv[i]);
88+ argv[i] = env->GetStringUTFChars (item, NULL );
89+ }
90+ free (argv);
91+ }
5492 if (RCL_RET_OK != ret) {
5593 std::string msg = " Failed to init context: " + std::string (rcl_get_error_string ().str );
5694 rcl_ret_t ignored_ret = rcl_init_options_fini (&init_options);
@@ -98,8 +136,15 @@ Java_org_ros2_rcljava_contexts_ContextImpl_nativeDispose(JNIEnv * env, jclass, j
98136
99137 rcl_context_t * context = reinterpret_cast <rcl_context_t *>(context_handle);
100138
101- rcl_ret_t ret = rcl_context_fini (context);
139+ // TODO(ivanpauno): Currently, calling `rcl_context_fini` in a zero initialized context fails:
140+ // That's incongruent with most other rcl objects.
141+ // rcl issue: https://github.com/ros2/rcl/issues/814
102142
143+ if (!context->impl ) {
144+ return ;
145+ }
146+
147+ rcl_ret_t ret = rcl_context_fini (context);
103148 if (RCL_RET_OK != ret) {
104149 std::string msg = " Failed to destroy context: " + std::string (rcl_get_error_string ().str );
105150 rcl_reset_error ();
0 commit comments