diff --git a/rcljava/src/main/java/org/ros2/rcljava/client/Client.java b/rcljava/src/main/java/org/ros2/rcljava/client/Client.java index 774ecec6..811aa2c5 100644 --- a/rcljava/src/main/java/org/ros2/rcljava/client/Client.java +++ b/rcljava/src/main/java/org/ros2/rcljava/client/Client.java @@ -26,9 +26,7 @@ import org.ros2.rcljava.service.RMWRequestId; public interface Client extends Disposable { - Class getRequestType(); - - Class getResponseType(); + ServiceDefinition getServiceDefinition(); void handleResponse(RMWRequestId header, U response); diff --git a/rcljava/src/main/java/org/ros2/rcljava/client/ClientImpl.java b/rcljava/src/main/java/org/ros2/rcljava/client/ClientImpl.java index 3c3187e3..442aa8ec 100644 --- a/rcljava/src/main/java/org/ros2/rcljava/client/ClientImpl.java +++ b/rcljava/src/main/java/org/ros2/rcljava/client/ClientImpl.java @@ -55,20 +55,25 @@ public class ClientImpl implements Client { private final String serviceName; private Map> pendingRequests; - private final Class requestType; - private final Class responseType; - - public ClientImpl(final WeakReference nodeReference, final long handle, - final String serviceName, final Class requestType, - final Class responseType) { + private final ServiceDefinition serviceDefinition; + + public ClientImpl( + final ServiceDefinition serviceDefinition, + final WeakReference nodeReference, + final long handle, + final String serviceName) + { this.nodeReference = nodeReference; this.handle = handle; this.serviceName = serviceName; - this.requestType = requestType; - this.responseType = responseType; + this.serviceDefinition = serviceDefinition; this.pendingRequests = new HashMap>(); } + public ServiceDefinition getServiceDefinition() { + return this.serviceDefinition; + } + public final Future asyncSendRequest(final U request) { return asyncSendRequest(request, new Consumer>() { @@ -112,14 +117,6 @@ private static native long nativeSendClientRequest( long handle, long requestFromJavaConverterHandle, long requestDestructorHandle, MessageDefinition requestMessage); - public final Class getRequestType() { - return this.requestType; - } - - public final Class getResponseType() { - return this.responseType; - } - /** * Destroy a ROS2 client (rcl_client_t). * diff --git a/rcljava/src/main/java/org/ros2/rcljava/executors/BaseExecutor.java b/rcljava/src/main/java/org/ros2/rcljava/executors/BaseExecutor.java index bd86e63a..5c43b6c4 100644 --- a/rcljava/src/main/java/org/ros2/rcljava/executors/BaseExecutor.java +++ b/rcljava/src/main/java/org/ros2/rcljava/executors/BaseExecutor.java @@ -118,18 +118,9 @@ protected void executeAnyExecutable(AnyExecutable anyExecutable) { } if (anyExecutable.service != null) { - Class requestType = anyExecutable.service.getRequestType(); - Class responseType = anyExecutable.service.getResponseType(); - - MessageDefinition requestMessage = null; - MessageDefinition responseMessage = null; - - try { - requestMessage = requestType.getDeclaredConstructor().newInstance(); - responseMessage = responseType.getDeclaredConstructor().newInstance(); - } catch (ReflectiveOperationException e) { - throw new IllegalStateException("Failed to instantiate service request/response"); - } + ServiceDefinition serviceDefinition = anyExecutable.service.getServiceDefinition(); + MessageDefinition requestMessage = serviceDefinition.newRequestInstance(); + MessageDefinition responseMessage = serviceDefinition.newResponseInstance(); if (requestMessage != null && responseMessage != null) { long requestFromJavaConverterHandle = requestMessage.getFromJavaConverterInstance(); @@ -140,28 +131,21 @@ protected void executeAnyExecutable(AnyExecutable anyExecutable) { long responseDestructorHandle = responseMessage.getDestructorInstance(); RMWRequestId rmwRequestId = - nativeTakeRequest(anyExecutable.service.getHandle(), requestFromJavaConverterHandle, - requestToJavaConverterHandle, requestDestructorHandle, requestMessage); + nativeTakeRequest(anyExecutable.service.getHandle(), requestFromJavaConverterHandle, + requestToJavaConverterHandle, requestDestructorHandle, requestMessage); if (rmwRequestId != null) { anyExecutable.service.executeCallback(rmwRequestId, requestMessage, responseMessage); - nativeSendServiceResponse(anyExecutable.service.getHandle(), rmwRequestId, - responseFromJavaConverterHandle, responseDestructorHandle, responseMessage); + nativeSendServiceResponse( + anyExecutable.service.getHandle(), rmwRequestId, + responseFromJavaConverterHandle, responseDestructorHandle, responseMessage); } } serviceHandles.remove(anyExecutable.service.getHandle()); } if (anyExecutable.client != null) { - Class requestType = anyExecutable.client.getRequestType(); - Class responseType = anyExecutable.client.getResponseType(); - - MessageDefinition responseMessage = null; - - try { - responseMessage = responseType.getDeclaredConstructor().newInstance(); - } catch (ReflectiveOperationException ie) { - throw new IllegalStateException("Failed to instantiate service response"); - } + ServiceDefinition serviceDefinition = anyExecutable.client.getServiceDefinition(); + MessageDefinition responseMessage = serviceDefinition.newResponseInstance(); if (responseMessage != null) { long responseFromJavaConverterHandle = responseMessage.getFromJavaConverterInstance(); diff --git a/rcljava/src/main/java/org/ros2/rcljava/node/Node.java b/rcljava/src/main/java/org/ros2/rcljava/node/Node.java index 63dc6b24..43d470d6 100644 --- a/rcljava/src/main/java/org/ros2/rcljava/node/Node.java +++ b/rcljava/src/main/java/org/ros2/rcljava/node/Node.java @@ -39,6 +39,8 @@ import org.ros2.rcljava.parameters.ParameterCallback; import org.ros2.rcljava.parameters.ParameterType; import org.ros2.rcljava.parameters.ParameterVariant; +import org.ros2.rcljava.parameters.client.AsyncParametersClient; +import org.ros2.rcljava.parameters.client.SyncParametersClient; import org.ros2.rcljava.publisher.Publisher; import org.ros2.rcljava.qos.QoSProfile; import org.ros2.rcljava.service.RMWRequestId; @@ -126,23 +128,24 @@ Publisher createPublisher( Publisher createPublisher( final Class messageType, final String topic); - Service createService(final Class serviceType, + Service createService( + final Class serviceType, final String serviceName, final TriConsumer callback, - final QoSProfile qosProfile) throws NoSuchFieldException, IllegalAccessException; + final QoSProfile qosProfile); - Service createService(final Class serviceType, + Service createService( + final Class serviceType, final String serviceName, final TriConsumer - callback) throws NoSuchFieldException, IllegalAccessException; + callback); Client createClient( - final Class serviceType, final String serviceName, final QoSProfile qosProfile) - throws NoSuchFieldException, IllegalAccessException; + final Class serviceType, final String serviceName, final QoSProfile qosProfile); - Client createClient(final Class serviceType, - final String serviceName) throws NoSuchFieldException, IllegalAccessException; + Client createClient( + final Class serviceType, final String serviceName); /** * Create an ActionServer<T>. @@ -263,6 +266,16 @@ ActionServer createActionServer(final Class a */ String getNamespace(); + /** + * Create an asynchronous parameter client. + */ + AsyncParametersClient createAsyncParametersClient(String nodeName); + + /** + * Create an synchronous parameter client. + */ + SyncParametersClient createSyncParametersClient(String nodeName); + /** * Declare and initialize a parameter, return the effective value. * diff --git a/rcljava/src/main/java/org/ros2/rcljava/node/NodeImpl.java b/rcljava/src/main/java/org/ros2/rcljava/node/NodeImpl.java index 3bfb0e4b..3ca6cfb6 100644 --- a/rcljava/src/main/java/org/ros2/rcljava/node/NodeImpl.java +++ b/rcljava/src/main/java/org/ros2/rcljava/node/NodeImpl.java @@ -44,6 +44,10 @@ import org.ros2.rcljava.parameters.ParameterNotDeclaredException; import org.ros2.rcljava.parameters.ParameterType; import org.ros2.rcljava.parameters.ParameterVariant; +import org.ros2.rcljava.parameters.client.AsyncParametersClient; +import org.ros2.rcljava.parameters.client.AsyncParametersClientImpl; +import org.ros2.rcljava.parameters.client.SyncParametersClient; +import org.ros2.rcljava.parameters.client.SyncParametersClientImpl; import org.ros2.rcljava.parameters.service.ParameterService; import org.ros2.rcljava.parameters.service.ParameterServiceImpl; import org.ros2.rcljava.publisher.Publisher; @@ -191,18 +195,8 @@ public NodeImpl(final long handle, final NodeOptions nodeOptions) { this.wall_clock = new Clock(ClockType.STEADY_TIME); this.timeSource = new TimeSource(this); this.timeSource.attachClock(this.clock); - try { - this.parameterService = nodeOptions.getStartParameterServices() ? - new ParameterServiceImpl(this) : null; - // TODO(ivanpauno): Modify createService, createClient so they don't declare - // NoSuchFieldException and IllegalAccessException checked exceptions. - // That only happens if the user passed the wrong Class object, and the exception should - // be rethrown as an unchecked IllegalArgumentException. - } catch (NoSuchFieldException ex) { - throw new IllegalArgumentException(ex.getMessage()); - } catch (IllegalAccessException ex) { - throw new IllegalArgumentException(ex.getMessage()); - } + this.parameterService = nodeOptions.getStartParameterServices() ? + new ParameterServiceImpl(this) : null; } /** @@ -340,30 +334,39 @@ private static native long nativeCreateServiceHand long handle, Class cls, String serviceName, long qosProfileHandle); public final Service createService(final Class serviceType, - final String serviceName, - final TriConsumer - callback, - final QoSProfile qosProfile) throws NoSuchFieldException, IllegalAccessException { - Class requestType = (Class) serviceType.getField("RequestType").get(null); - - Class responseType = (Class) serviceType.getField("ResponseType").get(null); - + final String serviceName, + final TriConsumer + callback, + final QoSProfile qosProfile) + { + T serviceDefinition; + try { + serviceDefinition = serviceType.getDeclaredConstructor().newInstance(); + } catch (ReflectiveOperationException e) { + throw new IllegalStateException("Failed to instantiate service definition"); + } long qosProfileHandle = RCLJava.convertQoSProfileToHandle(qosProfile); long serviceHandle = nativeCreateServiceHandle(this.handle, serviceType, serviceName, qosProfileHandle); RCLJava.disposeQoSProfile(qosProfileHandle); - Service service = new ServiceImpl(new WeakReference(this), serviceHandle, - serviceName, callback, requestType, responseType); + Service service = new ServiceImpl( + serviceDefinition, + new WeakReference(this), + serviceHandle, + serviceName, + callback); this.services.add(service); return service; } - public Service createService(final Class serviceType, - final String serviceName, - final TriConsumer - callback) throws NoSuchFieldException, IllegalAccessException { + public Service createService( + final Class serviceType, + final String serviceName, + final TriConsumer + callback) + { return this.createService(serviceType, serviceName, callback, QoSProfile.SERVICES_DEFAULT); } @@ -375,26 +378,29 @@ public final Collection getServices() { } public final Client createClient( - final Class serviceType, final String serviceName, final QoSProfile qosProfile) - throws NoSuchFieldException, IllegalAccessException { - Class requestType = (Class) serviceType.getField("RequestType").get(null); - - Class responseType = (Class) serviceType.getField("ResponseType").get(null); - + final Class serviceType, final String serviceName, final QoSProfile qosProfile) + { long qosProfileHandle = RCLJava.convertQoSProfileToHandle(qosProfile); long clientHandle = nativeCreateClientHandle(this.handle, serviceType, serviceName, qosProfileHandle); RCLJava.disposeQoSProfile(qosProfileHandle); + T serviceDefinition; + try { + serviceDefinition = serviceType.getDeclaredConstructor().newInstance(); + } catch (ReflectiveOperationException e) { + throw new IllegalStateException("Failed to instantiate service definition"); + } + Client client = new ClientImpl( - new WeakReference(this), clientHandle, serviceName, requestType, responseType); + serviceDefinition, new WeakReference(this), clientHandle, serviceName); this.clients.add(client); return client; } public Client createClient(final Class serviceType, - final String serviceName) throws NoSuchFieldException, IllegalAccessException { + final String serviceName) { return this.createClient(serviceType, serviceName, QoSProfile.SERVICES_DEFAULT); } @@ -531,6 +537,14 @@ public final String getNamespace() { return nativeGetNamespace(this.handle); } + public AsyncParametersClient createAsyncParametersClient(String nodeName) { + return new AsyncParametersClientImpl(this, nodeName); + } + + public SyncParametersClient createSyncParametersClient(String nodeName) { + return new SyncParametersClientImpl(this, nodeName); + } + public ParameterVariant declareParameter(ParameterVariant parameter) { return declareParameter(parameter, new rcl_interfaces.msg.ParameterDescriptor().setName(parameter.getName())); } diff --git a/rcljava/src/main/java/org/ros2/rcljava/parameters/client/AsyncParametersClientImpl.java b/rcljava/src/main/java/org/ros2/rcljava/parameters/client/AsyncParametersClientImpl.java index bfd01708..5de84b4f 100644 --- a/rcljava/src/main/java/org/ros2/rcljava/parameters/client/AsyncParametersClientImpl.java +++ b/rcljava/src/main/java/org/ros2/rcljava/parameters/client/AsyncParametersClientImpl.java @@ -49,7 +49,7 @@ public class AsyncParametersClientImpl implements AsyncParametersClient { private final Client describeParametersClient; public AsyncParametersClientImpl(final Node node, final String remoteName, - final QoSProfile qosProfile) throws NoSuchFieldException, IllegalAccessException { + final QoSProfile qosProfile) { this.node = node; if (remoteName != "") { this.remoteName = remoteName; @@ -84,17 +84,17 @@ public AsyncParametersClientImpl(final Node node, final String remoteName, } public AsyncParametersClientImpl(final Node node, final QoSProfile qosProfile) - throws NoSuchFieldException, IllegalAccessException { + { this(node, "", qosProfile); } public AsyncParametersClientImpl(final Node node, final String remoteName) - throws NoSuchFieldException, IllegalAccessException { + { this(node, remoteName, QoSProfile.PARAMETERS); } public AsyncParametersClientImpl(final Node node) - throws NoSuchFieldException, IllegalAccessException { + { this(node, "", QoSProfile.PARAMETERS); } diff --git a/rcljava/src/main/java/org/ros2/rcljava/parameters/client/SyncParametersClientImpl.java b/rcljava/src/main/java/org/ros2/rcljava/parameters/client/SyncParametersClientImpl.java index d2b4a78f..b8a0a323 100644 --- a/rcljava/src/main/java/org/ros2/rcljava/parameters/client/SyncParametersClientImpl.java +++ b/rcljava/src/main/java/org/ros2/rcljava/parameters/client/SyncParametersClientImpl.java @@ -55,44 +55,55 @@ public ConsumerHelper(RCLFuture resultFuture) { public AsyncParametersClient asyncParametersClient; - public SyncParametersClientImpl(final Node node, final String remoteName, - final QoSProfile qosProfile) throws NoSuchFieldException, IllegalAccessException { + public SyncParametersClientImpl( + final Node node, + final String remoteName, + final QoSProfile qosProfile) + { this.asyncParametersClient = new AsyncParametersClientImpl(node, remoteName, qosProfile); } public SyncParametersClientImpl(final Node node, final QoSProfile qosProfile) - throws NoSuchFieldException, IllegalAccessException { + { this(node, "", qosProfile); } public SyncParametersClientImpl(final Node node, final String remoteName) - throws NoSuchFieldException, IllegalAccessException { + { this(node, remoteName, QoSProfile.PARAMETERS); } public SyncParametersClientImpl(final Node node) - throws NoSuchFieldException, IllegalAccessException { + { this(node, "", QoSProfile.PARAMETERS); } - public SyncParametersClientImpl(final Executor executor, final Node node, final String remoteName, - final QoSProfile qosProfile) throws NoSuchFieldException, IllegalAccessException { + public SyncParametersClientImpl( + final Executor executor, + final Node node, + final String remoteName, + final QoSProfile qosProfile) + { this.executor = executor; this.asyncParametersClient = new AsyncParametersClientImpl(node, remoteName, qosProfile); } - public SyncParametersClientImpl(final Executor executor, final Node node, - final QoSProfile qosProfile) throws NoSuchFieldException, IllegalAccessException { + public SyncParametersClientImpl( + final Executor executor, + final Node node, + final QoSProfile qosProfile) + { this(executor, node, "", qosProfile); } - public SyncParametersClientImpl(final Executor executor, final Node node, final String remoteName) - throws NoSuchFieldException, IllegalAccessException { + public SyncParametersClientImpl( + final Executor executor, final Node node, final String remoteName) + { this(executor, node, remoteName, QoSProfile.PARAMETERS); } public SyncParametersClientImpl(final Executor executor, final Node node) - throws NoSuchFieldException, IllegalAccessException { + { this(executor, node, "", QoSProfile.PARAMETERS); } diff --git a/rcljava/src/main/java/org/ros2/rcljava/parameters/service/ParameterServiceImpl.java b/rcljava/src/main/java/org/ros2/rcljava/parameters/service/ParameterServiceImpl.java index 9d65ddd7..bc03b121 100644 --- a/rcljava/src/main/java/org/ros2/rcljava/parameters/service/ParameterServiceImpl.java +++ b/rcljava/src/main/java/org/ros2/rcljava/parameters/service/ParameterServiceImpl.java @@ -38,7 +38,7 @@ public class ParameterServiceImpl implements ParameterService { Service listParametersService; public ParameterServiceImpl(final Node node, final QoSProfile qosProfile) - throws NoSuchFieldException, IllegalAccessException { + { this.node = node; this.getParametersService = node.createService( rcl_interfaces.srv.GetParameters.class, @@ -146,7 +146,7 @@ public void accept(RMWRequestId rmwRequestId, qosProfile); } - public ParameterServiceImpl(final Node node) throws NoSuchFieldException, IllegalAccessException { + public ParameterServiceImpl(final Node node) { this(node, QoSProfile.PARAMETERS); } } diff --git a/rcljava/src/main/java/org/ros2/rcljava/service/Service.java b/rcljava/src/main/java/org/ros2/rcljava/service/Service.java index dfde9a09..289bad2b 100644 --- a/rcljava/src/main/java/org/ros2/rcljava/service/Service.java +++ b/rcljava/src/main/java/org/ros2/rcljava/service/Service.java @@ -21,9 +21,7 @@ import org.ros2.rcljava.interfaces.ServiceDefinition; public interface Service extends Disposable { - Class getRequestType(); - - Class getResponseType(); + ServiceDefinition getServiceDefinition(); void executeCallback(RMWRequestId rmwRequestId, MessageDefinition request, MessageDefinition response); diff --git a/rcljava/src/main/java/org/ros2/rcljava/service/ServiceImpl.java b/rcljava/src/main/java/org/ros2/rcljava/service/ServiceImpl.java index 0257813a..960a8424 100644 --- a/rcljava/src/main/java/org/ros2/rcljava/service/ServiceImpl.java +++ b/rcljava/src/main/java/org/ros2/rcljava/service/ServiceImpl.java @@ -45,28 +45,25 @@ public class ServiceImpl implements Service { private final TriConsumer callback; - private final Class requestType; - private final Class responseType; - - public ServiceImpl(final WeakReference nodeReference, final long handle, - final String serviceName, - final TriConsumer - callback, - final Class requestType, final Class responseType) { + private final ServiceDefinition serviceDefinition; + + public ServiceImpl( + final ServiceDefinition serviceDefinition, + final WeakReference nodeReference, + final long handle, + final String serviceName, + final TriConsumer + callback) + { this.nodeReference = nodeReference; this.handle = handle; this.serviceName = serviceName; this.callback = callback; - this.requestType = requestType; - this.responseType = responseType; + this.serviceDefinition = serviceDefinition; } - public final Class getRequestType() { - return this.requestType; - } - - public final Class getResponseType() { - return this.responseType; + public final ServiceDefinition getServiceDefinition() { + return this.serviceDefinition; } /** diff --git a/rcljava_common/src/main/java/org/ros2/rcljava/interfaces/ServiceDefinition.java b/rcljava_common/src/main/java/org/ros2/rcljava/interfaces/ServiceDefinition.java index 8e3bf79e..cade9a22 100644 --- a/rcljava_common/src/main/java/org/ros2/rcljava/interfaces/ServiceDefinition.java +++ b/rcljava_common/src/main/java/org/ros2/rcljava/interfaces/ServiceDefinition.java @@ -15,4 +15,7 @@ package org.ros2.rcljava.interfaces; -public interface ServiceDefinition {} +public interface ServiceDefinition { + MessageDefinition newRequestInstance(); + MessageDefinition newResponseInstance(); +} diff --git a/rosidl_generator_java/resource/srv.java.em b/rosidl_generator_java/resource/srv.java.em index 8bfb887c..a238ecfd 100644 --- a/rosidl_generator_java/resource/srv.java.em +++ b/rosidl_generator_java/resource/srv.java.em @@ -61,6 +61,14 @@ public class @(type_name) implements ServiceDefinition { } } + public @(type_name)_Request newRequestInstance() { + return new @(type_name)_Request(); + } + + public @(type_name)_Response newResponseInstance() { + return new @(type_name)_Response(); + } + public static native long getServiceTypeSupport(); public static final Class<@(type_name)_Request> RequestType = @(type_name)_Request.class;