Skip to content

Commit cf2ef07

Browse files
authored
Add methods to remove entities from Node (#110)
* Add methods to remove entities from Node When an entity is disposed, make sure to also remove it from the Node. This resolves an issue where invalid entities may be used by other classes or users. For example, a disposed Subscription being accessed by the executor. Fixes #105 Signed-off-by: Jacob Perron <[email protected]> * Add tests for disposing publishers, services, and clients Signed-off-by: Jacob Perron <[email protected]> * Rename test Signed-off-by: Jacob Perron <[email protected]>
1 parent 549c386 commit cf2ef07

File tree

9 files changed

+106
-3
lines changed

9 files changed

+106
-3
lines changed

rcljava/src/main/java/org/ros2/rcljava/client/ClientImpl.java

+1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ public final Class<MessageDefinition> getResponseType() {
131131
public final void dispose() {
132132
Node node = this.nodeReference.get();
133133
if (node != null) {
134+
node.removeClient(this);
134135
nativeDispose(node.getHandle(), this.handle);
135136
this.handle = 0;
136137
}

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

+49
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,55 @@ <T extends ServiceDefinition> Client<T> createClient(
122122
<T extends ServiceDefinition> Client<T> createClient(final Class<T> serviceType,
123123
final String serviceName) throws NoSuchFieldException, IllegalAccessException;
124124

125+
/**
126+
* Remove a Subscription created by this Node.
127+
*
128+
* Calling this method effectively invalidates the passed @{link Subscription}.
129+
* If the subscription was not created by this Node, then nothing happens.
130+
*
131+
* @param subscription The object to remove from this node.
132+
* @return true if the subscription was removed, false if the subscription was already
133+
* removed or was never created by this Node.
134+
*/
135+
boolean removeSubscription(final Subscription subscription);
136+
137+
/**
138+
* Remove a Publisher created by this Node.
139+
*
140+
* Calling this method effectively invalidates the passed @{link Publisher}.
141+
* If the publisher was not created by this Node, then nothing happens.
142+
*
143+
* @param publisher The object to remove from this node.
144+
* @return true if the publisher was removed, false if the publisher was already
145+
* removed or was never created by this Node.
146+
*/
147+
boolean removePublisher(final Publisher publisher);
148+
149+
/**
150+
* Remove a Service created by this Node.
151+
*
152+
* Calling this method effectively invalidates the passed @{link Service}.
153+
* If the service was not created by this Node, then nothing happens.
154+
*
155+
* @param service The object to remove from this node.
156+
* @return true if the service was removed, false if the service was already
157+
* removed or was never created by this Node.
158+
*/
159+
boolean removeService(final Service service);
160+
161+
/**
162+
* Remove a Client created by this Node.
163+
*
164+
* Calling this method effectively invalidates the passed @{link Client}.
165+
* If the client was not created by this Node, then nothing happens.
166+
*
167+
* @param client The object to remove from this node.
168+
* @return true if the client was removed, false if the client was already
169+
* removed or was never created by this Node.
170+
*/
171+
boolean removeClient(final Client client);
172+
173+
125174
WallTimer createWallTimer(final long period, final TimeUnit unit, final Callback callback);
126175

127176
String getName();

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

+28
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,20 @@ public final <T extends MessageDefinition> Subscription<T> createSubscription(
221221
return this.<T>createSubscription(messageType, topic, callback, QoSProfile.DEFAULT);
222222
}
223223

224+
/**
225+
* {@inheritDoc}
226+
*/
227+
public boolean removeSubscription(final Subscription subscription) {
228+
return this.subscriptions.remove(subscription);
229+
}
230+
231+
/**
232+
* {@inheritDoc}
233+
*/
234+
public boolean removePublisher(final Publisher publisher) {
235+
return this.publishers.remove(publisher);
236+
}
237+
224238
/**
225239
* {@inheritDoc}
226240
*/
@@ -300,6 +314,20 @@ public <T extends ServiceDefinition> Client<T> createClient(final Class<T> servi
300314
private static native <T extends ServiceDefinition> long nativeCreateClientHandle(
301315
long handle, Class<T> cls, String serviceName, long qosProfileHandle);
302316

317+
/**
318+
* {@inheritDoc}
319+
*/
320+
public boolean removeService(final Service service) {
321+
return this.services.remove(service);
322+
}
323+
324+
/**
325+
* {@inheritDoc}
326+
*/
327+
public boolean removeClient(final Client client) {
328+
return this.clients.remove(client);
329+
}
330+
303331
/**
304332
* {@inheritDoc}
305333
*/

rcljava/src/main/java/org/ros2/rcljava/publisher/PublisherImpl.java

+1
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ public final WeakReference<Node> getNodeReference() {
117117
public final void dispose() {
118118
Node node = this.nodeReference.get();
119119
if (node != null) {
120+
node.removePublisher(this);
120121
nativeDispose(node.getHandle(), this.handle);
121122
this.handle = 0;
122123
}

rcljava/src/main/java/org/ros2/rcljava/service/ServiceImpl.java

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ public final Class<MessageDefinition> getResponseType() {
8585
public final void dispose() {
8686
Node node = this.nodeReference.get();
8787
if (node != null) {
88+
node.removeService(this);
8889
nativeDispose(node.getHandle(), this.handle);
8990
this.handle = 0;
9091
}

rcljava/src/main/java/org/ros2/rcljava/subscription/SubscriptionImpl.java

+1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ public final WeakReference<Node> getNodeReference() {
129129
public final void dispose() {
130130
Node node = this.nodeReference.get();
131131
if (node != null) {
132+
node.removeSubscription(this);
132133
nativeDispose(node.getHandle(), this.handle);
133134
this.handle = 0;
134135
}

rcljava/src/test/java/org/ros2/rcljava/client/ClientTest.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,16 @@ public final void testAdd() throws Exception {
111111
// Check the contents of the response
112112
assertEquals(5, response.getSum());
113113

114-
// Cleanup
114+
assertEquals(1, node.getClients().size());
115+
assertEquals(1, node.getServices().size());
116+
117+
// We expect that calling dispose should result in a zero handle
118+
// and the reference is dropped from the Node
115119
client.dispose();
116120
assertEquals(0, client.getHandle());
121+
assertEquals(0, node.getClients().size());
117122
service.dispose();
118123
assertEquals(0, service.getHandle());
124+
assertEquals(0, node.getServices().size());
119125
}
120126
}

rcljava/src/test/java/org/ros2/rcljava/publisher/PublisherTest.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,22 @@
2525

2626
public class PublisherTest {
2727
@Test
28-
public final void testCreate() {
28+
public final void testCreateAndDispose() {
2929
RCLJava.rclJavaInit();
3030
Node node = RCLJava.createNode("test_node");
3131
Publisher<std_msgs.msg.String> publisher =
3232
node.<std_msgs.msg.String>createPublisher(std_msgs.msg.String.class, "test_topic");
3333
assertEquals(node.getHandle(), publisher.getNodeReference().get().getHandle());
3434
assertNotEquals(0, publisher.getNodeReference().get().getHandle());
3535
assertNotEquals(0, publisher.getHandle());
36+
assertEquals(1, node.getPublishers().size());
37+
38+
// We expect that calling dispose should result in a zero handle
39+
// and the reference is dropped from the Node
40+
publisher.dispose();
41+
assertEquals(0, publisher.getHandle());
42+
assertEquals(0, node.getPublishers().size());
43+
3644
RCLJava.shutdown();
3745
}
3846
}

rcljava/src/test/java/org/ros2/rcljava/subscription/SubscriptionTest.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
public class SubscriptionTest {
2828
@Test
29-
public final void testCreate() {
29+
public final void testCreateAndDispose() {
3030
RCLJava.rclJavaInit();
3131
Node node = RCLJava.createNode("test_node");
3232
Subscription<std_msgs.msg.String> subscription = node.<std_msgs.msg.String>createSubscription(
@@ -36,6 +36,14 @@ public void accept(final std_msgs.msg.String msg) {}
3636
assertEquals(node.getHandle(), subscription.getNodeReference().get().getHandle());
3737
assertNotEquals(0, subscription.getNodeReference().get().getHandle());
3838
assertNotEquals(0, subscription.getHandle());
39+
assertEquals(1, node.getSubscriptions().size());
40+
41+
// We expect that calling dispose should result in a zero handle
42+
// and the reference is dropped from the Node
43+
subscription.dispose();
44+
assertEquals(0, subscription.getHandle());
45+
assertEquals(0, node.getSubscriptions().size());
46+
3947
RCLJava.shutdown();
4048
}
4149
}

0 commit comments

Comments
 (0)