Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions rcljava/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ set(${PROJECT_NAME}_sources
"src/main/java/org/ros2/rcljava/node/ComposableNode.java"
"src/main/java/org/ros2/rcljava/node/Node.java"
"src/main/java/org/ros2/rcljava/node/NodeImpl.java"
"src/main/java/org/ros2/rcljava/node/NodeOptions.java"
"src/main/java/org/ros2/rcljava/parameters/client/AsyncParametersClient.java"
"src/main/java/org/ros2/rcljava/parameters/client/AsyncParametersClientImpl.java"
"src/main/java/org/ros2/rcljava/parameters/client/SyncParametersClient.java"
Expand Down Expand Up @@ -229,6 +230,7 @@ if(BUILD_TESTING)
"src/test/java/org/ros2/rcljava/SpinTest.java"
"src/test/java/org/ros2/rcljava/TimeTest.java"
# "src/test/java/org/ros2/rcljava/client/ClientTest.java"
"src/test/java/org/ros2/rcljava/node/NodeOptionsTest.java"
"src/test/java/org/ros2/rcljava/node/NodeParametersTest.java"
"src/test/java/org/ros2/rcljava/node/NodeUndeclaredParametersTest.java"
"src/test/java/org/ros2/rcljava/node/NodeTest.java"
Expand All @@ -244,6 +246,7 @@ if(BUILD_TESTING)
"org.ros2.rcljava.SpinTest"
"org.ros2.rcljava.TimeTest"
# "org.ros2.rcljava.client.ClientTest"
"org.ros2.rcljava.node.NodeOptionsTest"
"org.ros2.rcljava.node.NodeParametersTest"
"org.ros2.rcljava.node.NodeUndeclaredParametersTest"
"org.ros2.rcljava.node.NodeTest"
Expand Down
2 changes: 1 addition & 1 deletion rcljava/include/org_ros2_rcljava_RCLJava.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ JNICALL Java_org_ros2_rcljava_RCLJava_nativeCreateContextHandle(JNIEnv *, jclass
*/
JNIEXPORT jlong
JNICALL Java_org_ros2_rcljava_RCLJava_nativeCreateNodeHandle(
JNIEnv *, jclass, jstring, jstring, jlong);
JNIEnv *, jclass, jstring, jstring, jlong, jobject, jboolean, jboolean);

/*
* Class: org_ros2_rcljava_RCLJava
Expand Down
19 changes: 19 additions & 0 deletions rcljava/include/org_ros2_rcljava_node_NodeImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,25 @@
#ifdef __cplusplus
extern "C" {
#endif

/*
* Class: org_ros2_rcljava_node_NodeImpl
* Method: nativeGetName
* Signature: (J)Ljava/lang/String
*/
JNIEXPORT jstring
JNICALL Java_org_ros2_rcljava_node_NodeImpl_nativeGetName(
JNIEnv * env, jclass, jlong node_handle);

/*
* Class: org_ros2_rcljava_node_NodeImpl
* Method: nativeGetNamespace
* Signature: (J)Ljava/lang/String
*/
JNIEXPORT jstring
JNICALL Java_org_ros2_rcljava_node_NodeImpl_nativeGetNamespace(
JNIEnv * env, jclass, jlong node_handle);

/*
* Class: org_ros2_rcljava_node_NodeImpl
* Method: nativeCreatePublisherHandle
Expand Down
82 changes: 76 additions & 6 deletions rcljava/src/main/cpp/org_ros2_rcljava_RCLJava.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <cassert>
#include <cstdlib>
#include <string>
#include <vector>

#include "rcl/error_handling.h"
#include "rcl/node.h"
Expand Down Expand Up @@ -44,9 +45,47 @@ Java_org_ros2_rcljava_RCLJava_nativeCreateContextHandle(JNIEnv *, jclass)
return context_handle;
}

bool parse_arguments(JNIEnv * env, jobject cli_args, rcl_arguments_t * arguments)
{
// TODO(clalancette): we could probably make this faster by just doing these
// method lookups during some initialization time. But we'd have to add a lot
// more infrastructure for that, and we don't expect to call
// 'nativeCreateNodeHandle' that often, so I think this is OK for now.
jclass java_util_ArrayList = env->FindClass("java/util/ArrayList");
jmethodID java_util_ArrayList_size = env->GetMethodID(java_util_ArrayList, "size", "()I");
jmethodID java_util_ArrayList_get = env->GetMethodID(
java_util_ArrayList, "get", "(I)Ljava/lang/Object;");

*arguments = rcl_get_zero_initialized_arguments();
jint argc = env->CallIntMethod(cli_args, java_util_ArrayList_size);
std::vector<const char *> argv(argc);
for (jint i = 0; i < argc; ++i) {
jstring element =
static_cast<jstring>(env->CallObjectMethod(cli_args, java_util_ArrayList_get, i));
argv[i] = env->GetStringUTFChars(element, nullptr);
env->DeleteLocalRef(element);
}
rcl_ret_t ret = rcl_parse_arguments(argc, &argv[0], rcl_get_default_allocator(), arguments);
for (jint i = 0; i < argc; ++i) {
jstring element =
static_cast<jstring>(env->CallObjectMethod(cli_args, java_util_ArrayList_get, i));
env->ReleaseStringUTFChars(element, argv[i]);
env->DeleteLocalRef(element);
}
if (ret != RCL_RET_OK) {
std::string msg = "Failed to parse node arguments: " + std::string(rcl_get_error_string().str);
rcl_reset_error();
rcljava_throw_rclexception(env, ret, msg);
return false;
}

return true;
}

JNIEXPORT jlong JNICALL
Java_org_ros2_rcljava_RCLJava_nativeCreateNodeHandle(
JNIEnv * env, jclass, jstring jnode_name, jstring jnamespace, jlong context_handle)
JNIEnv * env, jclass, jstring jnode_name, jstring jnamespace, jlong context_handle,
jobject cli_args, jboolean use_global_arguments, jboolean enable_rosout)
{
const char * node_name_tmp = env->GetStringUTFChars(jnode_name, 0);
std::string node_name(node_name_tmp);
Expand All @@ -59,19 +98,50 @@ Java_org_ros2_rcljava_RCLJava_nativeCreateNodeHandle(
rcl_context_t * context = reinterpret_cast<rcl_context_t *>(context_handle);

rcl_node_t * node = static_cast<rcl_node_t *>(malloc(sizeof(rcl_node_t)));
if (node == nullptr) {
env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), "Failed to allocate node");
return 0;
}
*node = rcl_get_zero_initialized_node();

rcl_node_options_t default_options = rcl_node_get_default_options();
rcl_ret_t ret = rcl_node_init(
node, node_name.c_str(), namespace_.c_str(), context, &default_options);
rcl_arguments_t arguments;
if (!parse_arguments(env, cli_args, &arguments)) {
// All of the exception setup was done by parse_arguments, just return here.
free(node);
return 0;
}

rcl_node_options_t options = rcl_node_get_default_options();
options.use_global_arguments = use_global_arguments;
options.arguments = arguments;
options.enable_rosout = enable_rosout;
rcl_ret_t ret = rcl_node_init(node, node_name.c_str(), namespace_.c_str(), context, &options);
if (ret != RCL_RET_OK) {
std::string msg = "Failed to create node: " + std::string(rcl_get_error_string().str);
rcl_reset_error();
free(node);
if (rcl_arguments_fini(&arguments) != RCL_RET_OK) {
// We are already throwing an exception, just ignore the return here
}
rcljava_throw_rclexception(env, ret, msg);
return 0;
}
jlong node_handle = reinterpret_cast<jlong>(node);
return node_handle;

ret = rcl_arguments_fini(&arguments);
if (ret != RCL_RET_OK) {
// We failed to cleanup
std::string msg = "Failed to cleanup after creating node: " + std::string(
rcl_get_error_string().str);
rcl_reset_error();
if (rcl_node_fini(node) != RCL_RET_OK) {
// We are already throwing an exception, just ignore the return here
}
free(node);
rcljava_throw_rclexception(env, ret, msg);
return 0;
}

return reinterpret_cast<jlong>(node);
}

JNIEXPORT jstring JNICALL
Expand Down
14 changes: 14 additions & 0 deletions rcljava/src/main/cpp/org_ros2_rcljava_node_NodeImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@

using rcljava_common::exceptions::rcljava_throw_rclexception;

JNIEXPORT jstring JNICALL
Java_org_ros2_rcljava_node_NodeImpl_nativeGetName(
JNIEnv * env, jclass, jlong node_handle)
{
return env->NewStringUTF(rcl_node_get_name(reinterpret_cast<rcl_node_t *>(node_handle)));
}

JNIEXPORT jstring JNICALL
Java_org_ros2_rcljava_node_NodeImpl_nativeGetNamespace(
JNIEnv * env, jclass, jlong node_handle)
{
return env->NewStringUTF(rcl_node_get_namespace(reinterpret_cast<rcl_node_t *>(node_handle)));
}

JNIEXPORT jlong JNICALL
Java_org_ros2_rcljava_node_NodeImpl_nativeCreatePublisherHandle(
JNIEnv * env, jclass, jlong node_handle, jclass jmessage_class, jstring jtopic,
Expand Down
14 changes: 8 additions & 6 deletions rcljava/src/main/java/org/ros2/rcljava/RCLJava.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
Expand All @@ -33,6 +34,7 @@
import org.ros2.rcljava.node.ComposableNode;
import org.ros2.rcljava.node.Node;
import org.ros2.rcljava.node.NodeImpl;
import org.ros2.rcljava.node.NodeOptions;
import org.ros2.rcljava.publisher.Publisher;
import org.ros2.rcljava.qos.QoSProfile;
import org.ros2.rcljava.service.RMWRequestId;
Expand Down Expand Up @@ -177,7 +179,7 @@ public static synchronized void rclJavaInit() {
* @param contextHandle Pointer to a context (rcl_context_t) with which to associated the node.
* @return A pointer to the underlying ROS2 node structure.
*/
private static native long nativeCreateNodeHandle(String nodeName, String namespace, long contextHandle);
private static native long nativeCreateNodeHandle(String nodeName, String namespace, long contextHandle, ArrayList<String> arguments, boolean useGlobalArguments, boolean enableRosout);

/**
* @return The identifier of the currently active RMW implementation via the
Expand Down Expand Up @@ -234,7 +236,7 @@ public static Context createContext() {
* structure.
*/
public static Node createNode(final String nodeName) {
return createNode(nodeName, "", RCLJava.getDefaultContext(), false);
return createNode(nodeName, "", RCLJava.getDefaultContext(), new NodeOptions());
}

/**
Expand All @@ -246,12 +248,12 @@ public static Node createNode(final String nodeName) {
* structure.
*/
public static Node createNode(final String nodeName, final String namespace, final Context context) {
return createNode(nodeName, namespace, context, false);
return createNode(nodeName, namespace, context, new NodeOptions());
}

public static Node createNode(final String nodeName, final String namespace, final Context context, final boolean allowUndeclaredParameters) {
long nodeHandle = nativeCreateNodeHandle(nodeName, namespace, context.getHandle());
Node node = new NodeImpl(nodeHandle, nodeName, context, allowUndeclaredParameters);
public static Node createNode(final String nodeName, final String namespace, final Context context, final NodeOptions options) {
long nodeHandle = nativeCreateNodeHandle(nodeName, namespace, context.getHandle(), options.getCliArgs(), options.getUseGlobalArguments(), options.getEnableRosout());
Node node = new NodeImpl(nodeHandle, context, options.getAllowUndeclaredParameters());
nodes.add(node);
return node;
}
Expand Down
13 changes: 13 additions & 0 deletions rcljava/src/main/java/org/ros2/rcljava/node/Node.java
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,21 @@ <T extends ServiceDefinition> Client<T> createClient(final Class<T> serviceType,

WallTimer createWallTimer(final long period, final TimeUnit unit, final Callback callback);

/** Get the name of the node.
*
* @return The name of the node.
*/
String getName();

/** Get the namespace of the node.
*
* This namespace is the "node's" namespace, and therefore is not affected
* by any sub-namespace's that may affect entities created with this instance.
*
* @return The namespace of the node.
*/
String getNamespace();

/**
* Declare and initialize a parameter, return the effective value.
*
Expand Down
25 changes: 20 additions & 5 deletions rcljava/src/main/java/org/ros2/rcljava/node/NodeImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,6 @@ public class NodeImpl implements Node {
*/
private final Collection<Timer> timers;

private final String name;

private Object parametersMutex;

class ParameterAndDescriptor {
Expand All @@ -142,10 +140,9 @@ class ParameterAndDescriptor {
* @param handle A pointer to the underlying ROS2 node structure. Must not
* be zero.
*/
public NodeImpl(final long handle, final String name, final Context context, final boolean allowUndeclaredParameters) {
public NodeImpl(final long handle, final Context context, final boolean allowUndeclaredParameters) {
this.clock = new Clock(ClockType.SYSTEM_TIME);
this.handle = handle;
this.name = name;
this.context = context;
this.publishers = new LinkedBlockingQueue<Publisher>();
this.subscriptions = new LinkedBlockingQueue<Subscription>();
Expand All @@ -159,6 +156,20 @@ public NodeImpl(final long handle, final String name, final Context context, fin
this.parameterCallbacks = new ArrayList<ParameterCallback>();
}

/**
* Get the ROS 2 node name.
* @param handle A pointer to the underlying ROS2 node structure.
* @return The name of the node.
*/
private static native String nativeGetName(long handle);

/**
* Get the ROS 2 node namespace.
* @param handle A pointer to the underlying ROS2 node structure.
* @return The namespace of the node.
*/
private static native String nativeGetNamespace(long handle);

/**
* Create a ROS2 publisher (rcl_publisher_t) and return a pointer to
* it as an integer.
Expand Down Expand Up @@ -401,7 +412,11 @@ public final Collection<Timer> getTimers() {
* {@inheritDoc}
*/
public final String getName() {
return this.name;
return nativeGetName(this.handle);
}

public final String getNamespace() {
return nativeGetNamespace(this.handle);
}

public ParameterVariant declareParameter(ParameterVariant parameter) {
Expand Down
68 changes: 68 additions & 0 deletions rcljava/src/main/java/org/ros2/rcljava/node/NodeOptions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* Copyright 2020 Open Source Robotics Foundation, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.ros2.rcljava.node;

import java.util.ArrayList;

public class NodeOptions {
private boolean useGlobalArguments;
private boolean enableRosout;
private boolean allowUndeclaredParameters;
private ArrayList<String> cliArgs;

public NodeOptions() {
this.useGlobalArguments = true;
this.enableRosout = true;
this.allowUndeclaredParameters = false;
this.cliArgs = new ArrayList<String>();
}

public final boolean getUseGlobalArguments() {
return this.useGlobalArguments;
}

public NodeOptions setUseGlobalArguments(boolean useGlobal) {
this.useGlobalArguments = useGlobal;
return this;
}

public final boolean getEnableRosout() {
return this.enableRosout;
}

public NodeOptions setEnableRosout(boolean enable) {
this.enableRosout = enable;
return this;
}

public final boolean getAllowUndeclaredParameters() {
return this.allowUndeclaredParameters;
}

public NodeOptions setAllowUndeclaredParameters(boolean allow) {
this.allowUndeclaredParameters = allow;
return this;
}

public final ArrayList<String> getCliArgs() {
return this.cliArgs;
}

public NodeOptions setCliArgs(ArrayList<String> newArgs) {
this.cliArgs = newArgs;
return this;
}
}
Loading