diff --git a/rcljava/CMakeLists.txt b/rcljava/CMakeLists.txt index 991af41a..6015398c 100644 --- a/rcljava/CMakeLists.txt +++ b/rcljava/CMakeLists.txt @@ -87,6 +87,13 @@ set(${PROJECT_NAME}_sources "src/main/java/org/ros2/rcljava/Publisher.java" "src/main/java/org/ros2/rcljava/Subscription.java" "src/main/java/org/ros2/rcljava/Consumer.java" + "src/main/java/org/ros2/rcljava/Log.java" + "src/main/java/org/ros2/rcljava/QoSProfile.java" + "src/main/java/org/ros2/rcljava/NativeUtils.java" + "src/main/java/org/ros2/rcljava/exception/ImplementationAlreadyImportedException.java" + "src/main/java/org/ros2/rcljava/exception/InvalidRCLJAVAImplementation.java" + "src/main/java/org/ros2/rcljava/exception/NoImplementationAvailableException.java" + "src/main/java/org/ros2/rcljava/exception/NotInitializedException.java" ) add_jar("${PROJECT_NAME}_jar" diff --git a/rcljava/src/main/java/org/ros2/rcljava/Consumer.java b/rcljava/src/main/java/org/ros2/rcljava/Consumer.java index 6c240a42..be19c8e8 100644 --- a/rcljava/src/main/java/org/ros2/rcljava/Consumer.java +++ b/rcljava/src/main/java/org/ros2/rcljava/Consumer.java @@ -14,6 +14,11 @@ */ package org.ros2.rcljava; +/** + * + * + * @author Esteve Fernandez + */ public interface Consumer { void accept(T t); } diff --git a/rcljava/src/main/java/org/ros2/rcljava/Log.java b/rcljava/src/main/java/org/ros2/rcljava/Log.java new file mode 100644 index 00000000..42c3f079 --- /dev/null +++ b/rcljava/src/main/java/org/ros2/rcljava/Log.java @@ -0,0 +1,36 @@ +/* Copyright 2016 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; + +import org.ros2.rcljava.exception.NoImplementationAvailableException; + +/** + * Not define in ROS2. + * + * @author Mickael Gaillard + */ +public class Log { + + public Log() { } + + public void fatal(Exception e) { + throw new NoImplementationAvailableException(e); + } + + public void info(String string) { + throw new NoImplementationAvailableException(new Exception(string)); + } + +} diff --git a/rcljava/src/main/java/org/ros2/rcljava/NativeUtils.java b/rcljava/src/main/java/org/ros2/rcljava/NativeUtils.java new file mode 100644 index 00000000..8f84ee19 --- /dev/null +++ b/rcljava/src/main/java/org/ros2/rcljava/NativeUtils.java @@ -0,0 +1,34 @@ +package org.ros2.rcljava; + +import java.util.Vector; + +public abstract class NativeUtils { + + private static java.lang.reflect.Field LIBRARIES; + + static { + try { + LIBRARIES = ClassLoader.class.getDeclaredField("loadedLibraryNames"); + LIBRARIES.setAccessible(true); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } catch (SecurityException e) { + e.printStackTrace(); + } + } + + @SuppressWarnings("unchecked") + public static String[] getLoadedLibraries(final ClassLoader loader) { + Vector libraries = new Vector(); + + try { + libraries = (Vector) LIBRARIES.get(loader); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + return libraries.toArray(new String[] {}); + } +} diff --git a/rcljava/src/main/java/org/ros2/rcljava/Node.java b/rcljava/src/main/java/org/ros2/rcljava/Node.java index 2b4c8478..474f01f9 100644 --- a/rcljava/src/main/java/org/ros2/rcljava/Node.java +++ b/rcljava/src/main/java/org/ros2/rcljava/Node.java @@ -15,49 +15,105 @@ package org.ros2.rcljava; import java.lang.ref.WeakReference; - import java.util.ArrayList; import java.util.List; +import java.util.logging.Logger; +/** + *

Node ROS2.

+ *

+ * @author Esteve Fernandez + * @author Mickael Gaillard + */ public class Node { - static { - try { - System.loadLibrary("rcljavaNode__" + RCLJava.getRMWIdentifier()); - } catch (UnsatisfiedLinkError e) { - System.err.println("Native code library failed to load.\n" + e); - System.exit(1); - } + private static Logger logger = Logger.getLogger(RCLJava.LOG_NAME); + + static { + RCLJava.loadLibrary("rcljavaNode__" + RCLJava.getRMWIdentifier()); } - private long nodeHandle; - private List subscriptions = new ArrayList(); + /** Node handler */ + private final long nodeHandle; + + /** List of subscriptions */ + private final List> subscriptions; + + // Native call. + private static native long nativeCreatePublisherHandle( + long nodeHandle, Class cls, String topic); + + private static native long nativeCreateSubscriptionHandle( + long nodeHandle, Class cls, String topic); + /** + * Constructor of Node. + * @param nodeHandle Handler to the node. + */ public Node(long nodeHandle) { this.nodeHandle = nodeHandle; + this.subscriptions = new ArrayList>(); } - private static native long nativeCreatePublisherHandle( - long nodeHandle, Class cls, String topic); + /** + *

Create a new publisher.

+ * + * @param Message definition. + * @param message Message class. + * @param topic Topic to publish. + * @param qos QOS profile. + * @return Publisher instance. + */ + public Publisher createPublisher(Class message, String topic, QoSProfile qos) { + logger.fine("Create Publisher : " + topic); + long publisherHandle = Node.nativeCreatePublisherHandle(this.nodeHandle, message, topic); - private static native long nativeCreateSubscriptionHandle( - long nodeHandle, Class cls, String topic); + Publisher publisher = new Publisher(this.nodeHandle, publisherHandle, message, topic, qos); + RCLJava.publisherReferences.add(new WeakReference>(publisher)); - public Publisher createPublisher(Class cls, String topic) { - long publisherHandle = nativeCreatePublisherHandle(this.nodeHandle, cls, topic); - Publisher publisher = new Publisher(this.nodeHandle, publisherHandle); - RCLJava.publisherReferences.add(new WeakReference(publisher)); return publisher; } - public Subscription createSubscription(Class cls, String topic, Consumer callback) { - long subscriptionHandle = nativeCreateSubscriptionHandle(this.nodeHandle, cls, topic); + /** + *

Create a new Subscriber with callback.

+ * + * @param Message definition. + * @param message Message Class + * @param topic Topic to subscribe. + * @param callback Function to call on recieve. + * @param qos QOS profile. + * @return + */ + public Subscription createSubscription( + Class message, + String topic, + Consumer callback, + QoSProfile qos) { + logger.fine("Create Subscription : " + topic); + long subscriptionHandle = Node.nativeCreateSubscriptionHandle(this.nodeHandle, message, topic); - Subscription subscription = new Subscription(this.nodeHandle, subscriptionHandle, cls, topic, callback); + Subscription subscription = new Subscription( + this.nodeHandle, + subscriptionHandle, + message, + topic, + callback, + qos); this.subscriptions.add(subscription); return subscription; } - public List getSubscriptions() { + /** + * Get list of Subscriptions. + * @return ArrayList of Subscriptions + */ + public List> getSubscriptions() { return this.subscriptions; } + + /** + * Release all Publisher ressource. + */ + public void dispose() { + //TODO Implement on JNI + } } diff --git a/rcljava/src/main/java/org/ros2/rcljava/Publisher.java b/rcljava/src/main/java/org/ros2/rcljava/Publisher.java index c964d509..7c00a7c1 100644 --- a/rcljava/src/main/java/org/ros2/rcljava/Publisher.java +++ b/rcljava/src/main/java/org/ros2/rcljava/Publisher.java @@ -14,34 +14,84 @@ */ package org.ros2.rcljava; +/** + *

Publisher of node.

+ *

+ * @param Message Type. + * @author Esteve Fernandez + * @author Mickael Gaillard + */ public class Publisher { - static { - try { - System.loadLibrary("rcljavaPublisher__" + RCLJava.getRMWIdentifier()); - } catch (UnsatisfiedLinkError e) { - System.err.println("Native code library failed to load.\n" + e); - System.exit(1); - } - } - private long nodeHandle; - private long publisherHandle; + /** Node Handler. */ + private final long nodeHandle; + + /** Publisher Hander. */ + private final long publisherHandle; + + /** Message Type. */ + private final Class messageType; + + /** Topic to publish. */ + private final String topic; + + /** Quality of Service profil. */ + private final QoSProfile qosProfile; + + // Native call. + private static native void nativePublish(long publisherHandle, T msg); + private static native void nativeDispose(long nodeHandle, long publisherHandle); - public Publisher(long nodeHandle, long publisherHandle) { + static { + RCLJava.loadLibrary("rcljavaPublisher__" + RCLJava.getRMWIdentifier()); + } + + /** + * Constructor of Publisher. + * + * @param nodeHandle Node handler initialize. + * @param publisherHandle Publisher handler. + * @param messageType Message type. + * @param topic Topic to publish. + * @param qos Quality of Service profile. + */ + public Publisher(long nodeHandle, long publisherHandle, Class messageType, String topic, QoSProfile qosProfile) { this.nodeHandle = nodeHandle; this.publisherHandle = publisherHandle; + this.messageType = messageType; + this.topic = topic; + this.qosProfile = qosProfile; } - private static native void nativePublish(long publisherHandle, T msg); - + /** + * Publish a message. + * @param msg Message to publish. + */ public void publish(T msg) { - nativePublish(this.publisherHandle, msg); + Publisher.nativePublish(this.publisherHandle, msg); //TODO(theos) add qosProfile } - private static native void nativeDispose( - long nodeHandle, long publisherHandle); + /** + * Get message type. + * @return + */ + public Class getMsgType() { + return this.messageType; + } + + /** + * Get topic name. + * @return + */ + public String getTopic() { + return this.topic; + } + /** + * Release all Publisher ressource. + */ public void dispose() { - nativeDispose(this.nodeHandle, this.publisherHandle); + //TODO implement to JNI + //Publisher.nativeDispose(this.nodeHandle, this.publisherHandle); } } diff --git a/rcljava/src/main/java/org/ros2/rcljava/QoSProfile.java b/rcljava/src/main/java/org/ros2/rcljava/QoSProfile.java new file mode 100644 index 00000000..c10b0693 --- /dev/null +++ b/rcljava/src/main/java/org/ros2/rcljava/QoSProfile.java @@ -0,0 +1,127 @@ +/* Copyright 2016 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; + +/** + *

Quality of Service Profile

+ *

TODO Not full implemented !!

+ * @author Mickael Gaillard + */ +public class QoSProfile { + + /** Default Depth level */ + public static final int DEPTH_SYSTEM_DEFAULT = 0; + + /** Reliability Policy enum. */ + public enum ReliabilityPolicy { + SYSTEM_DEFAULT, + RELIABLE, + BEST_EFFORT + } + + /** History Policy enum. */ + public enum HistoryPolicy { + SYSTEM_DEFAULT, + KEEP_LAST, + KEEP_ALL + } + + /** Durability Policy enum. */ + public enum DurabilityPolicy { + SYSTEM_DEFAULT, + TRANSIENT_LOCAL, + VOLATILE + } + + /** Sensor QOS Profile */ + public static final QoSProfile PROFILE_SENSOR_DATA = new QoSProfile( + HistoryPolicy.KEEP_LAST, + 5, + ReliabilityPolicy.BEST_EFFORT, + DurabilityPolicy.SYSTEM_DEFAULT + ); + + /** Parameter QOS Profile */ + public static final QoSProfile PROFILE_PARAMETER = new QoSProfile( + HistoryPolicy.KEEP_LAST, + 1000, + ReliabilityPolicy.RELIABLE, + DurabilityPolicy.SYSTEM_DEFAULT + ); + + /** Default QOS Profile */ + public static final QoSProfile PROFILE_DEFAULT = new QoSProfile( + HistoryPolicy.KEEP_ALL, + 10, + ReliabilityPolicy.RELIABLE, + DurabilityPolicy.SYSTEM_DEFAULT + ); + + /** Services default QOS Profile */ + public static final QoSProfile PROFILE_SERVICES_DEFAULT = new QoSProfile( + HistoryPolicy.KEEP_LAST, + 10, + ReliabilityPolicy.RELIABLE, + DurabilityPolicy.TRANSIENT_LOCAL + ); + + /** Parameter events QOS Profile */ + public static final QoSProfile PROFILE_PARAMETER_EVENTS = new QoSProfile( + HistoryPolicy.KEEP_ALL, + 1000, + ReliabilityPolicy.RELIABLE, + DurabilityPolicy.SYSTEM_DEFAULT + ); + + /** System default QOS Profile */ + public static final QoSProfile PROFILE_SYSTEM_DEFAULT = new QoSProfile( + HistoryPolicy.SYSTEM_DEFAULT, + DEPTH_SYSTEM_DEFAULT, + ReliabilityPolicy.SYSTEM_DEFAULT, + DurabilityPolicy.SYSTEM_DEFAULT + ); + + /** History Policy */ + protected final HistoryPolicy history; + + /** Depth */ + protected final int depth; + + /** Reliability Policy */ + protected final ReliabilityPolicy reliability; + + /** Durability Policy */ + protected final DurabilityPolicy durability; + + /** + * Constuctor. + * + * @param history + * @param depth + * @param reliability + * @param durability + */ + public QoSProfile( + HistoryPolicy history, + int depth, + ReliabilityPolicy reliability, + DurabilityPolicy durability) { + + this.history = history; + this.depth = depth; + this.reliability = reliability; + this.durability = durability; + } +} diff --git a/rcljava/src/main/java/org/ros2/rcljava/RCLJava.java b/rcljava/src/main/java/org/ros2/rcljava/RCLJava.java index 9a67c376..a626290b 100644 --- a/rcljava/src/main/java/org/ros2/rcljava/RCLJava.java +++ b/rcljava/src/main/java/org/ros2/rcljava/RCLJava.java @@ -15,21 +15,87 @@ package org.ros2.rcljava; import java.lang.ref.WeakReference; - import java.util.Queue; -import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.logging.SimpleFormatter; + +import org.ros2.rcljava.exception.NoImplementationAvailableException; import java.util.Map; import java.util.concurrent.ConcurrentSkipListMap; +/** + *

ROS2 java client wrapper.

+ *

JNI call of ROS2 c client.

+ * + * @author Esteve Fernandez + */ public class RCLJava { + + public static final String LOG_NAME = RCLJava.class.getName(); + + private static Logger logger = Logger.getLogger(LOG_NAME); + + /** Global List/Queue of publishers. */ public static Queue publisherReferences = new LinkedBlockingQueue(); + /** Current ROS2 middleware implementation use. */ + private static String rmwImplementation = null; + + /** ROS2 client is initialized. */ + private static boolean initialized = false; + + /** List of ROS2 middleware supported. */ + private static final Map rmwToTypesupport = new ConcurrentSkipListMap() { + /** Serial Id */ + private static final long serialVersionUID = 1L; + + { + put("rmw_fastrtps_cpp", "rosidl_typesupport_introspection_c"); + put("rmw_opensplice_cpp", "rosidl_typesupport_opensplice_c"); + put("rmw_connext_cpp", "rosidl_typesupport_connext_c"); + put("rmw_connext_dynamic_cpp", "rosidl_typesupport_introspection_c"); + } + }; + + // Natives definitions + private static native void nativeRCLJavaInit(); + private static native long nativeCreateNodeHandle(String nodeName); + private static native boolean nativeOk(); + private static native String nativeGetRMWIdentifier(); + private static native void nativeShutdown(); + private static native long nativeGetZeroInitializedWaitSet(); + private static native void nativeWaitSetInit(long waitSetHandle, int numberOfSubscriptions, int numberOfGuardConditions, int numberOfTimers); + private static native void nativeWaitSetClearSubscriptions(long waitSetHandle); + private static native void nativeWaitSetAddSubscription(long waitSetHandle, long subscriptionHandle); + private static native void nativeWait(long waitSetHandle); + private static native Object nativeTake(long SubscriptionHandle, Class msgType); + + /** Release all ressources at shutdown. */ static { + logger.setLevel(Level.ALL); + ConsoleHandler handler = new ConsoleHandler(); + handler.setFormatter(new SimpleFormatter()); + logger.addHandler(handler); + handler.setLevel(Level.INFO); + + Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { - for(WeakReference publisherReference : publisherReferences) { + logger.fine("Shutdown..."); + + String[] list = NativeUtils.getLoadedLibraries(RCLJava.class.getClassLoader()); + StringBuilder msgLog = new StringBuilder(); + for (String key : list) { + msgLog.append(key); + msgLog.append("\n"); + } + logger.fine("Native libraries Loaded: \n" + msgLog.toString()); + + for(WeakReference> publisherReference : RCLJava.publisherReferences) { if(publisherReference.get() != null) { publisherReference.get().dispose(); } @@ -38,112 +104,167 @@ public void run() { }); } - private static String rmwImplementation = null; - private static boolean initialized = false; - - private static final Map rmwToTypesupport = new ConcurrentSkipListMap() {{ - put("rmw_fastrtps_cpp", "rosidl_typesupport_introspection_c"); - put("rmw_opensplice_cpp", "rosidl_typesupport_opensplice_c"); - put("rmw_connext_cpp", "rosidl_typesupport_connext_c"); - put("rmw_connext_dynamic_cpp", "rosidl_typesupport_introspection_c"); - }}; - + /** + *

Global initialization of rcl.

+ *

+ * Unless otherwise noted, this must be called + * before using any rcl functions. + *

+ * This function can only be run once after starting the program, and once + * after each call to rcl_shutdown. Repeated calls will fail with + * RCL_RET_ALREADY_INIT. This function is not thread safe. + *

+ */ public static void rclJavaInit() { - synchronized(RCLJava.class) { - if (!initialized) { + synchronized (RCLJava.class) { + if (!RCLJava.initialized) { + String libpath = System.getProperty("java.library.path"); + logger.fine("Native Library path : \n" + libpath.replace(':', '\n')); + if (RCLJava.rmwImplementation == null) { - for(Map.Entry entry : rmwToTypesupport.entrySet()) { + for (Map.Entry entry : rmwToTypesupport.entrySet()) { try { - setRMWImplementation(entry.getKey()); + logger.config("Try to load native " + entry.getKey() + "..."); + RCLJava.setRMWImplementation(entry.getKey()); + logger.config(entry.getKey() + " loaded !"); break; - } catch(UnsatisfiedLinkError ule) { - // TODO(esteve): handle exception - } catch(Exception e) { - // TODO(esteve): handle exception + } catch (NoImplementationAvailableException e) { + logger.config(entry.getKey() + " not available ! (" + e.getMessage() + ")"); } } } + if (RCLJava.rmwImplementation == null) { - System.err.println("No RMW implementation found"); + logger.severe("No RMW implementation found..."); System.exit(1); } else { - nativeRCLJavaInit(); - initialized = true; + RCLJava.nativeRCLJavaInit(); + RCLJava.initialized = true; } } } } - private static native void nativeRCLJavaInit(); - - private static native long nativeCreateNodeHandle(String nodeName); + /** + * Node Reference of native node. + * + * @param nodeName Name of the node. + * @return Instance of Node Reference. + */ + public static Node createNode(String nodeName) { + logger.fine("Create Node stack : " + nodeName); + long nodeHandle = RCLJava.nativeCreateNodeHandle(nodeName); - public static String getTypesupportIdentifier() { - String typesupportIdentifier = rmwToTypesupport.get(nativeGetRMWIdentifier()); - return typesupportIdentifier; + return new Node(nodeHandle); } - public static void setRMWImplementation(String rmwImplementation) throws Exception { - synchronized(RCLJava.class) { - System.loadLibrary("rcljavaRCLJava__" + rmwImplementation); - RCLJava.rmwImplementation = rmwImplementation; + /** + *

Wait for once loop.

+ * @param node + */ + public static void spinOnce(Node node) { + long waitSetHandle = RCLJava.nativeGetZeroInitializedWaitSet(); + + RCLJava.nativeWaitSetInit(waitSetHandle, node.getSubscriptions().size(), 0, 0); + RCLJava.nativeWaitSetClearSubscriptions(waitSetHandle); + + for(Subscription subscription : node.getSubscriptions()) { + RCLJava.nativeWaitSetAddSubscription(waitSetHandle, subscription.getSubscriptionHandle()); } - } - private static native String nativeGetRMWIdentifier(); + RCLJava.nativeWait(waitSetHandle); - public static String getRMWIdentifier() { - return nativeGetRMWIdentifier(); + for(Subscription subscription : node.getSubscriptions()) { + Object msg = RCLJava.nativeTake(subscription.getSubscriptionHandle(), subscription.getMsgType()); + if (msg != null) { + subscription.getCallback().accept(msg); + } + } } - private static native boolean nativeOk(); - + /** + * Check if native is ready. + * + * @see rcl_node_is_valid(const rcl_node_t * node); + * @return true if the node is valid, else false. + */ public static boolean ok() { - return nativeOk(); + return RCLJava.nativeOk(); } - public static Node createNode(String nodeName) { - long nodeHandle = nativeCreateNodeHandle(nodeName); - Node node = new Node(nodeHandle); - return node; + /** + *

Signal global shutdown of RCLJava.

+ *

+ * This function does not have to be + * called on exit, but does have to be called making a repeat call to + * RCLJava.rclJavaInit. + *

+ * This function can only be called once after each call to RCLJava.rclJavaInit. + *

+ */ + public static void shutdown() { + logger.fine("Shutdown..."); + RCLJava.nativeShutdown(); } - public static void spinOnce(Node node) { - long waitSetHandle = nativeGetZeroInitializedWaitSet(); - - nativeWaitSetInit(waitSetHandle, node.getSubscriptions().size(), 0, 0); - - nativeWaitSetClearSubscriptions(waitSetHandle); - - for(Subscription subscription : node.getSubscriptions()) { - nativeWaitSetAddSubscription(waitSetHandle, subscription.getSubscriptionHandle()); - } - - nativeWait(waitSetHandle); - - for(Subscription subscription : node.getSubscriptions()) { - Object msg = nativeTake(subscription.getSubscriptionHandle(), subscription.getMsgType()); - if (msg != null) { - subscription.getCallback().accept(msg); - } - } + /** + * Get ROS Midleware indentifier. + * + * @return indentifier. + */ + public static String getRMWIdentifier() { + return RCLJava.nativeGetRMWIdentifier(); } - private static native void nativeShutdown(); + /** + *

Get identifier of the ROS2 middleware use.

+ *

TODO rename to list of RMW available.

+ * @return Identifier string of ROS2 middleware. + */ + public static String getTypesupportIdentifier() { + String typesupportIdentifier = rmwToTypesupport.get(RCLJava.getRMWIdentifier()); - public static void shutdown() { - nativeShutdown(); + return typesupportIdentifier; } - private static native long nativeGetZeroInitializedWaitSet(); - - private static native void nativeWaitSetInit(long waitSetHandle, int numberOfSubscriptions, int numberOfGuardConditions, int numberOfTimers); - - private static native void nativeWaitSetClearSubscriptions(long waitSetHandle); + /** + *

Switch of ROS2 middleware implementation

+ *

TODO need to check implementation available.

+ * @param rmwImplementation + * @throws NoImplementationAvailableException + */ + public static void setRMWImplementation(String rmwImplementation) + throws NoImplementationAvailableException { - private static native void nativeWaitSetAddSubscription(long waitSetHandle, long subscriptionHandle); + synchronized(RCLJava.class) { + String file = "rcljavaRCLJava__" + rmwImplementation; + logger.fine("Load native file : lib" + file + ".so"); - private static native void nativeWait(long waitSetHandle); + try { + System.loadLibrary(file); + RCLJava.rmwImplementation = rmwImplementation; + } catch (UnsatisfiedLinkError ule) { + throw new NoImplementationAvailableException(ule); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } - private static native Object nativeTake(long SubscriptionHandle, Class msgType); + /** + *

Load Native ROS library

+ *

load from java.library.path .

+ * @param name Name of the library. + */ + public static void loadLibrary(String name) { + synchronized(RCLJava.class) { + logger.fine("Load native file : lib" + name + ".so"); + try { + System.loadLibrary(name); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load.\n" + e); + System.exit(1); + } + } + } } diff --git a/rcljava/src/main/java/org/ros2/rcljava/Subscription.java b/rcljava/src/main/java/org/ros2/rcljava/Subscription.java index a40d2ecb..44253d84 100644 --- a/rcljava/src/main/java/org/ros2/rcljava/Subscription.java +++ b/rcljava/src/main/java/org/ros2/rcljava/Subscription.java @@ -14,31 +14,78 @@ */ package org.ros2.rcljava; +/** + *

Subscrition of node.

+ *

+ * @param Message Type. + * @author Esteve Fernandez + * @author Mickael Gaillard + */ public class Subscription { - private long nodeHandle; - private long subscriptionHandle; - private Class msgType; - private String topic; - private Consumer callback; + /** Node Handler. */ + private final long nodeHandle; + + /** Subsciption Hander. */ + private final long subscriptionHandle; + + /** Message Type. */ + private final Class messageType; + + /** Topic subscribed. */ + private final String topic; + + /** Callback. */ + private final Consumer callback; + + /** Quality of Service profil. */ + private final QoSProfile qosProfile; + + // Native call. + private static native void nativeDispose(long nodeHandle, long publisherHandle); - public Subscription(long nodeHandle, long subscriptionHandle, Class msgType, String topic, Consumer callback) { + public Subscription(long nodeHandle, long subscriptionHandle, Class messageType, String topic, Consumer callback, QoSProfile qosProfile) { this.nodeHandle = nodeHandle; this.subscriptionHandle = subscriptionHandle; - this.msgType = msgType; + this.messageType = messageType; this.topic = topic; this.callback = callback; + this.qosProfile = qosProfile; } + /** + * Get Callback. + * @return + */ public Consumer getCallback() { - return callback; + return this.callback; } + public long getSubscriptionHandle() { + return this.subscriptionHandle; + } + + /** + * Get message type. + * @return + */ public Class getMsgType() { - return msgType; + return this.messageType; } - public long getSubscriptionHandle() { - return subscriptionHandle; + /** + * Get topic name. + * @return + */ + public String getTopic() { + return this.topic; + } + + /** + * Release all Publisher ressource. + */ + public void dispose() { + //TODO implement to JNI + // Subscription.nativeDispose(this.nodeHandle, this.subscriptionHandle); } } diff --git a/rcljava/src/main/java/org/ros2/rcljava/exception/ImplementationAlreadyImportedException.java b/rcljava/src/main/java/org/ros2/rcljava/exception/ImplementationAlreadyImportedException.java new file mode 100644 index 00000000..d225a55f --- /dev/null +++ b/rcljava/src/main/java/org/ros2/rcljava/exception/ImplementationAlreadyImportedException.java @@ -0,0 +1,34 @@ +/* Copyright 2016 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.exception; + +/** + * Raised on select_rmw_implemenation() after import_rmw_implementation() has + * been called. + * + * @author Mickael Gaillard + */ +public class ImplementationAlreadyImportedException extends Exception { + + /** + * Constructor. + * + * @param cause + */ + public ImplementationAlreadyImportedException(Throwable cause) { + super("rmw implementation already imported", cause); + } + +} diff --git a/rcljava/src/main/java/org/ros2/rcljava/exception/InvalidRCLJAVAImplementation.java b/rcljava/src/main/java/org/ros2/rcljava/exception/InvalidRCLJAVAImplementation.java new file mode 100644 index 00000000..e97e8ee8 --- /dev/null +++ b/rcljava/src/main/java/org/ros2/rcljava/exception/InvalidRCLJAVAImplementation.java @@ -0,0 +1,34 @@ +/* Copyright 2016 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.exception; + +/** + * Raised when an invalid RCLPYImplementation is requested. + * + * @author Mickael Gaillard + * + */ +public class InvalidRCLJAVAImplementation extends Exception { + + /** + * Constructor. + * + * @param cause + */ + public InvalidRCLJAVAImplementation(Throwable cause) { + super("requested invalid rmw implementation", cause); + } + +} diff --git a/rcljava/src/main/java/org/ros2/rcljava/exception/NoImplementationAvailableException.java b/rcljava/src/main/java/org/ros2/rcljava/exception/NoImplementationAvailableException.java new file mode 100644 index 00000000..49305510 --- /dev/null +++ b/rcljava/src/main/java/org/ros2/rcljava/exception/NoImplementationAvailableException.java @@ -0,0 +1,36 @@ +/* Copyright 2016 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.exception; + +/** + * Raised when there is no rmw implementation with a Java extension available. + * + * @author Mickael Gaillard + * + */ +public class NoImplementationAvailableException extends RuntimeException { + + /** Serial ID */ + private static final long serialVersionUID = -2351440132432398102L; + + /** + * Constructor. + * + * @param cause + */ + public NoImplementationAvailableException(Throwable cause) { + super("no rmw implementation with a Java extension available", cause); + } +} diff --git a/rcljava/src/main/java/org/ros2/rcljava/exception/NotInitializedException.java b/rcljava/src/main/java/org/ros2/rcljava/exception/NotInitializedException.java new file mode 100644 index 00000000..d6c1ffa9 --- /dev/null +++ b/rcljava/src/main/java/org/ros2/rcljava/exception/NotInitializedException.java @@ -0,0 +1,33 @@ +/* Copyright 2016 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.exception; + +/** + * Raised when the rcljava implementation is accessed before RclJava(). + * + * @author Mickael Gaillard + * + */ +public class NotInitializedException extends Exception { + + /** + * Constructor. + * + * @param cause + */ + public NotInitializedException(Throwable cause) { + super("RclJava() has not been called", cause); + } +} diff --git a/rosidl_generator_java/resource/msg.java.template b/rosidl_generator_java/resource/msg.java.template index 57b72dfd..4c18f309 100644 --- a/rosidl_generator_java/resource/msg.java.template +++ b/rosidl_generator_java/resource/msg.java.template @@ -12,12 +12,7 @@ import @(field.type.pkg_name).msg.@(field.type.type); public class @(type_name) { static { - try { - System.loadLibrary("@(spec.base_type.pkg_name)_@(type_name)_s__" + RCLJavaProxy.getTypesupportIdentifier()); - } catch (UnsatisfiedLinkError e) { - System.err.println("Native code library failed to load.\n" + e); - System.exit(1); - } + RCLJavaProxy.loadLibrary("@(spec.base_type.pkg_name)_@(type_name)_s__" + RCLJavaProxy.getTypesupportIdentifier()); } public static native long getFromJavaConverter(); diff --git a/rosidl_generator_java/rosidl_generator_java/__init__.py b/rosidl_generator_java/rosidl_generator_java/__init__.py index 8b114e22..4e0ebd4f 100644 --- a/rosidl_generator_java/rosidl_generator_java/__init__.py +++ b/rosidl_generator_java/rosidl_generator_java/__init__.py @@ -135,7 +135,7 @@ def get_builtin_java_type(type_, use_primitives=True): return 'byte' if use_primitives else 'Byte' if type_ == 'char': - return 'char' if use_primitives else 'Char' + return 'char' if use_primitives else 'Character' if type_ == 'float32': return 'float' if use_primitives else 'Float' diff --git a/rosidl_generator_java/src/main/java/org/ros2/rosidl_generator_java/RCLJavaProxy.java b/rosidl_generator_java/src/main/java/org/ros2/rosidl_generator_java/RCLJavaProxy.java index 0901482d..5efa0157 100644 --- a/rosidl_generator_java/src/main/java/org/ros2/rosidl_generator_java/RCLJavaProxy.java +++ b/rosidl_generator_java/src/main/java/org/ros2/rosidl_generator_java/RCLJavaProxy.java @@ -41,4 +41,13 @@ public static synchronized String getRMWIdentifier() { } } + public static synchronized void loadLibrary(String name) { + try { + Class c = Class.forName("org.ros2.rcljava.RCLJava"); + Method m = c.getDeclaredMethod("loadLibrary", String.class); + Object o = m.invoke(null, name); + } catch(Exception e) { + // TODO(esteve): handle exception + } + } }