Skip to content

Commit cc1bacf

Browse files
committed
Add abstractions and minimal implementation of rcl events (osrf#4)
Signed-off-by: Ivan Santiago Paunovic <[email protected]>
1 parent 5670b3f commit cc1bacf

File tree

8 files changed

+434
-0
lines changed

8 files changed

+434
-0
lines changed

rcljava/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ set(${PROJECT_NAME}_jni_sources
5959
"src/main/cpp/org_ros2_rcljava_client_ClientImpl.cpp"
6060
"src/main/cpp/org_ros2_rcljava_contexts_ContextImpl.cpp"
6161
"src/main/cpp/org_ros2_rcljava_executors_BaseExecutor.cpp"
62+
"src/main/cpp/org_ros2_rcljava_events_EventHandlerImpl.cpp"
6263
"src/main/cpp/org_ros2_rcljava_node_NodeImpl.cpp"
6364
"src/main/cpp/org_ros2_rcljava_publisher_PublisherImpl.cpp"
6465
"src/main/cpp/org_ros2_rcljava_service_ServiceImpl.cpp"
@@ -125,6 +126,9 @@ set(${PROJECT_NAME}_sources
125126
"src/main/java/org/ros2/rcljava/consumers/BiConsumer.java"
126127
"src/main/java/org/ros2/rcljava/consumers/Consumer.java"
127128
"src/main/java/org/ros2/rcljava/consumers/TriConsumer.java"
129+
"src/main/java/org/ros2/rcljava/events/EventHandler.java"
130+
"src/main/java/org/ros2/rcljava/events/EventHandlerImpl.java"
131+
"src/main/java/org/ros2/rcljava/events/EventStatus.java"
128132
"src/main/java/org/ros2/rcljava/executors/AnyExecutable.java"
129133
"src/main/java/org/ros2/rcljava/executors/BaseExecutor.java"
130134
"src/main/java/org/ros2/rcljava/executors/Executor.java"
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2020 Open Source Robotics Foundation, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <jni.h>
16+
/* Header for class org_ros2_rcljava_events_EventHandlerImpl */
17+
18+
#ifndef ORG_ROS2_RCLJAVA_EVENTS_EVENTHANDLERIMPL_H_
19+
#define ORG_ROS2_RCLJAVA_EVENTS_EVENTHANDLERIMPL_H_
20+
#ifdef __cplusplus
21+
extern "C" {
22+
#endif
23+
24+
/*
25+
* Class: org_ros2_rcljava_events_EventHandlerImpl
26+
* Method: nativeDispose
27+
* Signature: (J)V
28+
*/
29+
JNIEXPORT void
30+
JNICALL Java_org_ros2_rcljava_events_EventHandlerImpl_nativeDispose(JNIEnv *, jclass, jlong event_handle);
31+
32+
/*
33+
* Class: org_ros2_rcljava_events_EventHandlerImpl
34+
* Method: nativeTake
35+
* Signature: (JJ)V
36+
*/
37+
JNIEXPORT void
38+
JNICALL Java_org_ros2_rcljava_events_EventHandlerImpl_nativeTake(
39+
JNIEnv *, jclass, jlong event_handle, jlong event_status_handle);
40+
41+
#ifdef __cplusplus
42+
}
43+
#endif
44+
#endif // ORG_ROS2_RCLJAVA_EVENTS_EVENTHANDLERIMPL_H_
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright 2020 Open Source Robotics Foundation, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <jni.h>
16+
17+
#include <string>
18+
19+
#include "rcl/error_handling.h"
20+
#include "rcl/event.h"
21+
22+
#include "rcljava_common/exceptions.hpp"
23+
24+
#include "org_ros2_rcljava_events_EventHandlerImpl.h"
25+
26+
using rcljava_common::exceptions::rcljava_throw_exception;
27+
using rcljava_common::exceptions::rcljava_throw_rclexception;
28+
29+
JNIEXPORT void JNICALL
30+
Java_org_ros2_rcljava_events_EventHandlerImpl_nativeDispose(
31+
JNIEnv * env, jclass, jlong event_handle)
32+
{
33+
if (event_handle == 0) {
34+
// everything is ok, already destroyed
35+
return;
36+
}
37+
38+
auto * event = reinterpret_cast<rcl_event_t *>(event_handle);
39+
40+
rcl_ret_t ret = rcl_event_fini(event);
41+
42+
if (RCL_RET_OK != ret) {
43+
std::string msg = "Failed to destroy event: " + std::string(rcl_get_error_string().str);
44+
rcl_reset_error();
45+
rcljava_throw_exception(env, "java/lang/IllegalStateException", msg);
46+
}
47+
}
48+
49+
JNIEXPORT void JNICALL
50+
Java_org_ros2_rcljava_events_EventHandlerImpl_nativeTake(JNIEnv *env, jclass, jlong event_handle, jlong event_status_handle)
51+
{
52+
auto * event = reinterpret_cast<rcl_event_t *>(event_handle);
53+
if (!event) {
54+
rcljava_throw_exception(
55+
env,
56+
"java/lang/IllegalArgumentException",
57+
"The underlying rcl_event_t has been already disposed");
58+
}
59+
void * event_status = reinterpret_cast<void *>(event_status_handle);
60+
if (!event_status) {
61+
rcljava_throw_exception(
62+
env,
63+
"java/lang/IllegalArgumentException",
64+
"The passed event status is NULL");
65+
}
66+
rcl_ret_t ret = rcl_take_event(event, event_status);
67+
if (RCL_RET_OK != ret) {
68+
rcljava_throw_rclexception(env, ret, rcl_get_error_string().str);
69+
rcl_reset_error();
70+
}
71+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2020 Open Source Robotics Foundation, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package org.ros2.rcljava.events;
16+
17+
import java.lang.ref.WeakReference;
18+
19+
import org.ros2.rcljava.interfaces.Disposable;
20+
import org.ros2.rcljava.events.EventStatus;
21+
22+
/**
23+
* This class serves as a bridge between a rcl_event_t and RCLJava.
24+
* An EventHandler must be created via
25+
* @{link Publisher#createEventHandler(Class&lt;T&gt;, Consumer&lt;T&gt;)}
26+
* @{link Subscription#createEventHandler(Class&lt;T&gt;, Consumer&lt;T&gt;)}
27+
*
28+
* @param <T> The event status type.
29+
* @param <ParentT> The parent class type.
30+
*/
31+
public interface EventHandler<T extends EventStatus, ParentT extends Disposable> extends Disposable {
32+
/**
33+
* @return The event status type.
34+
*/
35+
Class<T> getEventStatusType();
36+
37+
/**
38+
* @return The parent entity type.
39+
*/
40+
Class<ParentT> getParentType();
41+
42+
/**
43+
* @return A weak reference to the parent.
44+
*/
45+
WeakReference<ParentT> getParentReference();
46+
47+
/**
48+
* @return Execute the registered event callback
49+
*/
50+
void executeCallback();
51+
}
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
// Copyright 2020 Open Source Robotics Foundation, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package org.ros2.rcljava.events;
16+
17+
import java.lang.ref.WeakReference;
18+
import java.lang.reflect.InvocationTargetException;
19+
20+
import org.ros2.rcljava.common.JNIUtils;
21+
import org.ros2.rcljava.consumers.Consumer;
22+
import org.ros2.rcljava.events.EventHandler;
23+
import org.ros2.rcljava.events.EventStatus;
24+
import org.ros2.rcljava.interfaces.Disposable;
25+
26+
import org.slf4j.Logger;
27+
import org.slf4j.LoggerFactory;
28+
29+
/**
30+
* This class serves as a bridge between a rcl_event_t and RCLJava.
31+
* An EventHandler must be created via
32+
* @{link Publisher#createEventHandler(Class&lt;T&gt;, Consumer&lt;T&gt;)}
33+
* @{link Subscription#createEventHandler(Class&lt;T&gt;, Consumer&lt;T&gt;)}
34+
*
35+
* @param <T> The status event type.
36+
* @param <ParentT> The parent class type.
37+
*/
38+
public class EventHandlerImpl<
39+
T extends EventStatus,
40+
ParentT extends Disposable>
41+
implements EventHandler<T, ParentT> {
42+
private static final Logger logger = LoggerFactory.getLogger(EventHandlerImpl.class);
43+
44+
static {
45+
try {
46+
JNIUtils.loadImplementation(EventHandlerImpl.class);
47+
} catch (UnsatisfiedLinkError ule) {
48+
logger.error("Native code library failed to load.\n" + ule);
49+
System.exit(1);
50+
}
51+
}
52+
53+
/**
54+
* Constructor.
55+
*
56+
* @param parentType The <code>Class</code> type of the parent.
57+
* It can be either a @{link org.ros2.rcljava.Publisher} or a
58+
* @{link org.ros2.rcljava.Subscription} class.
59+
* @param parentReference A {@link java.lang.ref.WeakReference} to the
60+
* @{link org.ros2.rcljava.Publisher} or @{link org.ros2.rcljava.Subscription}
61+
* that created this event handler.
62+
* @param handle A pointer to the underlying ROS 2 event structure, as an integer.
63+
* Must not be zero.
64+
* @param eventStatusType The <code>Class</code> of the messages that this
65+
* subscription will receive. We need this because of Java's type erasure,
66+
* which doesn't allow us to use the generic parameter of
67+
* @{link org.ros2.rcljava.Subscription} directly.
68+
* @param callback The callback function that will be called when the event
69+
* is triggered.
70+
*/
71+
public EventHandlerImpl(
72+
final Class<ParentT> parentType,
73+
final WeakReference<ParentT> parentReference,
74+
final long handle,
75+
final Class<T> eventStatusType,
76+
final Consumer<T> callback) {
77+
this.parentType = parentType;
78+
this.parentReference = parentReference;
79+
this.handle = handle;
80+
this.eventStatusType = eventStatusType;
81+
this.callback = callback;
82+
}
83+
84+
/**
85+
* {@inheritDoc}
86+
*/
87+
public final Class<T> getEventStatusType() {
88+
return this.eventStatusType;
89+
}
90+
91+
/**
92+
* {@inheritDoc}
93+
*/
94+
public final Class<ParentT> getParentType() {
95+
return this.parentType;
96+
}
97+
98+
/**
99+
* {@inheritDoc}
100+
*/
101+
public final WeakReference<ParentT> getParentReference() {
102+
return this.parentReference;
103+
}
104+
105+
/**
106+
* {@inheritDoc}
107+
*/
108+
public final long getHandle() {
109+
return this.handle;
110+
}
111+
112+
/**
113+
* Destroy a ROS 2 event (rcl_event_t).
114+
*
115+
* @param handle A pointer to the underlying ROS 2 event structure,
116+
* as an integer. Must not be zero.
117+
*/
118+
private static native void nativeDispose(long handle);
119+
120+
/**
121+
* {@inheritDoc}
122+
*/
123+
public final void dispose() {
124+
nativeDispose(this.handle);
125+
this.handle = 0;
126+
}
127+
128+
/**
129+
* Takes the RCL event status and returns a pointer to it.
130+
*
131+
* @param event_handle A pointer to the underlying ROS 2 event (rcl_event_t).
132+
* @param event_status_handle A pointer to the underlying ROS 2 event status (void *).
133+
* Must not be zero.
134+
*/
135+
private static native void nativeTake(long event_handle, long event_status_handle);
136+
137+
/**
138+
* {@inheritDoc}
139+
*/
140+
public final void executeCallback() {
141+
T eventStatus = null;
142+
try {
143+
eventStatus = this.eventStatusType.getDeclaredConstructor().newInstance();
144+
} catch (NoSuchMethodException nme) {
145+
nme.printStackTrace();
146+
} catch (InvocationTargetException ite) {
147+
ite.printStackTrace();
148+
} catch (InstantiationException ie) {
149+
ie.printStackTrace();
150+
} catch (IllegalAccessException iae) {
151+
iae.printStackTrace();
152+
}
153+
long nativeEventStatusHandle = eventStatus.allocateRCLStatusEvent();
154+
nativeTake(this.handle, nativeEventStatusHandle);
155+
eventStatus.fromRCLEvent(nativeEventStatusHandle);
156+
eventStatus.deallocateRCLStatusEvent(nativeEventStatusHandle);
157+
callback.accept(eventStatus);
158+
}
159+
160+
private final Class<T> eventStatusType;
161+
private final Class<ParentT> parentType;
162+
private final WeakReference<ParentT> parentReference;
163+
private long handle;
164+
private final Consumer<T> callback;
165+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2020 Open Source Robotics Foundation, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package org.ros2.rcljava.events;
16+
17+
import org.ros2.rcljava.interfaces.Disposable;
18+
19+
/**
20+
* This class serves as a bridge between ROS2's rcl event status types and RCLJava.
21+
*/
22+
public interface EventStatus {
23+
/**
24+
* Allocates an rcl event status.
25+
*
26+
* @return A pointer to the allocated status.
27+
*/
28+
long allocateRCLStatusEvent();
29+
30+
/**
31+
* Deallocates an rcl event status.
32+
*
33+
* @param handle Pointer to a previously allocated event status.
34+
*/
35+
void deallocateRCLStatusEvent(long handle);
36+
37+
/**
38+
* Loads the event with the data of the rcl event status.
39+
*
40+
* @param handle A pointer to the underlying event status.
41+
*/
42+
void fromRCLEvent(long handle);
43+
}

0 commit comments

Comments
 (0)