diff --git a/rcljava/CMakeLists.txt b/rcljava/CMakeLists.txt index 7c1115bc..36fd4d80 100644 --- a/rcljava/CMakeLists.txt +++ b/rcljava/CMakeLists.txt @@ -143,6 +143,7 @@ set(${PROJECT_NAME}_sources "src/main/java/org/ros2/rcljava/action/GoalStatus.java" "src/main/java/org/ros2/rcljava/client/Client.java" "src/main/java/org/ros2/rcljava/client/ClientImpl.java" + "src/main/java/org/ros2/rcljava/client/ResponseFuture.java" "src/main/java/org/ros2/rcljava/concurrent/Callback.java" "src/main/java/org/ros2/rcljava/concurrent/RCLFuture.java" "src/main/java/org/ros2/rcljava/contexts/Context.java" 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 811aa2c5..8043cf6f 100644 --- a/rcljava/src/main/java/org/ros2/rcljava/client/Client.java +++ b/rcljava/src/main/java/org/ros2/rcljava/client/Client.java @@ -30,11 +30,13 @@ public interface Client extends Disposable { void handleResponse(RMWRequestId header, U response); - Future asyncSendRequest( + ResponseFuture asyncSendRequest( final U request); - Future asyncSendRequest( + ResponseFuture asyncSendRequest( final U request, final Consumer> callback); + + boolean removePendingRequest(ResponseFuture future); /** * Check if the service server is available. 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 f48a3892..c8496fc2 100644 --- a/rcljava/src/main/java/org/ros2/rcljava/client/ClientImpl.java +++ b/rcljava/src/main/java/org/ros2/rcljava/client/ClientImpl.java @@ -28,7 +28,6 @@ import org.ros2.rcljava.RCLJava; import org.ros2.rcljava.common.JNIUtils; -import org.ros2.rcljava.concurrent.RCLFuture; import org.ros2.rcljava.consumers.Consumer; import org.ros2.rcljava.interfaces.MessageDefinition; import org.ros2.rcljava.interfaces.ServiceDefinition; @@ -53,7 +52,7 @@ public class ClientImpl implements Client { private final WeakReference nodeReference; private long handle; private final String serviceName; - private Map> pendingRequests; + private Map> pendingRequests; private final ServiceDefinition serviceDefinition; @@ -67,43 +66,52 @@ public ClientImpl( this.handle = handle; this.serviceName = serviceName; this.serviceDefinition = serviceDefinition; - this.pendingRequests = new HashMap>(); + this.pendingRequests = new HashMap>(); } public ServiceDefinition getServiceDefinition() { return this.serviceDefinition; } - public final Future + public final ResponseFuture asyncSendRequest(final U request) { return asyncSendRequest(request, new Consumer>() { public void accept(Future input) {} }); } - public final Future + public final ResponseFuture asyncSendRequest(final U request, final Consumer> callback) { synchronized (pendingRequests) { long sequenceNumber = nativeSendClientRequest( handle, request.getFromJavaConverterInstance(), request.getDestructorInstance(), request); - RCLFuture future = new RCLFuture(); + ResponseFuture future = new ResponseFuture(sequenceNumber); - Map.Entry entry = - new AbstractMap.SimpleEntry(callback, future); + Map.Entry entry = + new AbstractMap.SimpleEntry(callback, future); pendingRequests.put(sequenceNumber, entry); return future; } } + public final boolean + removePendingRequest(ResponseFuture future) { + synchronized (pendingRequests) { + Map.Entry entry = pendingRequests.remove( + future.getRequestSequenceNumber()); + return entry != null; + } + } + public final void handleResponse( final RMWRequestId header, final U response) { synchronized (pendingRequests) { long sequenceNumber = header.sequenceNumber; - Map.Entry entry = pendingRequests.remove(sequenceNumber); + Map.Entry entry = pendingRequests.remove(sequenceNumber); if (entry != null) { Consumer callback = entry.getKey(); - RCLFuture future = entry.getValue(); + ResponseFuture future = entry.getValue(); future.set(response); callback.accept(future); return; diff --git a/rcljava/src/main/java/org/ros2/rcljava/client/ResponseFuture.java b/rcljava/src/main/java/org/ros2/rcljava/client/ResponseFuture.java new file mode 100644 index 00000000..9c89fbef --- /dev/null +++ b/rcljava/src/main/java/org/ros2/rcljava/client/ResponseFuture.java @@ -0,0 +1,29 @@ +/* Copyright 2021 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.client; + +import org.ros2.rcljava.concurrent.RCLFuture; + + +public class ResponseFuture extends RCLFuture { + public ResponseFuture(long requestSequenceNumber) { + this.requestSequenceNumber = requestSequenceNumber; + } + public long getRequestSequenceNumber() { + return this.requestSequenceNumber; + } + private long requestSequenceNumber; +} diff --git a/rcljava/src/test/java/org/ros2/rcljava/client/ClientTest.java b/rcljava/src/test/java/org/ros2/rcljava/client/ClientTest.java index 71e95218..03b4a558 100644 --- a/rcljava/src/test/java/org/ros2/rcljava/client/ClientTest.java +++ b/rcljava/src/test/java/org/ros2/rcljava/client/ClientTest.java @@ -16,6 +16,7 @@ package org.ros2.rcljava.client; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; @@ -131,4 +132,29 @@ public final void testAdd() throws Exception { service.dispose(); assertEquals(0, service.getHandle()); } + + @Test + public final void testRemovePendingRequest() throws Exception { + RCLFuture consumerFuture = + new RCLFuture(); + + TestClientConsumer clientConsumer = new TestClientConsumer(consumerFuture); + + Service service = node.createService( + rcljava.srv.AddTwoInts.class, "add_two_ints", clientConsumer); + + rcljava.srv.AddTwoInts_Request request = new rcljava.srv.AddTwoInts_Request(); + request.setA(2); + request.setB(3); + + Client client = + node.createClient(rcljava.srv.AddTwoInts.class, "add_two_ints"); + + assertTrue(client.waitForService(Duration.ofSeconds(10))); + + ResponseFuture responseFuture = client.asyncSendRequest(request); + + assertTrue(client.removePendingRequest(responseFuture)); + assertFalse(client.removePendingRequest(responseFuture)); + } }