|
| 1 | +Java Binding High Level Design |
| 2 | +============================== |
| 3 | + |
| 4 | +Overview |
| 5 | +-------- |
| 6 | + |
| 7 | +This document describes the high level design of the Java binding mechanism used |
| 8 | +by the Azure IoT Gateway SDK. It details how Java modules running inside of the |
| 9 | +JVM will interact with the native gateway core. |
| 10 | + |
| 11 | +Design |
| 12 | +------ |
| 13 | + |
| 14 | + |
| 15 | + |
| 16 | +Java Module Host |
| 17 | +---------------- |
| 18 | + |
| 19 | +The **Java Module Host** is a C module that |
| 20 | + |
| 21 | +1. Creates the JVM (Java Virtual Machine) the first time a Java module is |
| 22 | + attempting to connect to the gateway. |
| 23 | + |
| 24 | +2. Brokers calls **to** the Java module (create, destroy, receive). |
| 25 | + |
| 26 | +Because [JNI](http://docs.oracle.com/javase/8/docs/technotes/guides/jni/) (Java |
| 27 | +Native Interface) only allows one JVM instance per process, the **Java Module |
| 28 | +Host** will create a JVM **only once** when the first Java module is loading. |
| 29 | +Subsequent attempts to load additional Java modules will load and run those |
| 30 | +modules in the same JVM that was originally created. The JSON configuration for |
| 31 | +this module will be similar to the configuration for the Node Module Host: |
| 32 | + |
| 33 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ json |
| 34 | +{ |
| 35 | + "modules": [ |
| 36 | + { |
| 37 | + "module name": "java_poller", |
| 38 | + "module path": "/path/to/java_module_host.so|.dll", |
| 39 | + "args": { |
| 40 | + "class_path": "/path/to/relevant/class/files", |
| 41 | + "class_name": "Poller", |
| 42 | + "args": { |
| 43 | + "frequency": 30 |
| 44 | + }, |
| 45 | + "jvm_options": { |
| 46 | + "version": 8, |
| 47 | + "debug": true, |
| 48 | + "debug_port": 9876, |
| 49 | + "verbose": false, |
| 50 | + "additional_options": [ |
| 51 | + "-Djava.version=1.8" |
| 52 | + ] |
| 53 | + } |
| 54 | + } |
| 55 | + } |
| 56 | + ] |
| 57 | +} |
| 58 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 59 | + |
| 60 | +or: |
| 61 | + |
| 62 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ json |
| 63 | +{ |
| 64 | + "modules": [ |
| 65 | + { |
| 66 | + "module name": "java_poller", |
| 67 | + "module path": "/path/to/java_module_host.so|.dll", |
| 68 | + "tags": ["java"], |
| 69 | + "args": { |
| 70 | + "class_path": "/path/to/relevant/class/files", |
| 71 | + "class_name": "Poller", |
| 72 | + "args": { |
| 73 | + "frequency": 30 |
| 74 | + } |
| 75 | + } |
| 76 | + } |
| 77 | + ] |
| 78 | +} |
| 79 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 80 | + |
| 81 | +*You might have noticed a tags section. When processing the input JSON |
| 82 | +configuration file, the Gateway SDK will insert everything within the JSON |
| 83 | +object for the specified tag within the tags array into the args section for the |
| 84 | +corresponding module (please see \_\_\_\_ for more detailed guidance on |
| 85 | +constructing a JSON configuration).* |
| 86 | + |
| 87 | + |
| 88 | + |
| 89 | +As usual, the `module path` specifies the path to the DLL/SO that implements the |
| 90 | +**Java Module Host**. The `args.class_path` specifies the path to the directory |
| 91 | +where all necessary Java class files are located, `args.class_name` is the name |
| 92 | +of the class that implements the module code, and finally `args.jvm_options` is |
| 93 | +a JSON object containing any options to be passed to the JVM upon creation. |
| 94 | + |
| 95 | + |
| 96 | + |
| 97 | +Gateway Module (Java) |
| 98 | +--------------------- |
| 99 | + |
| 100 | +The **Java Module Host** will handle calling into the gateway module written in |
| 101 | +Java when necessary, therefore each module written in Java must implement the |
| 102 | +same `IGatewayModule` interface shown below: |
| 103 | + |
| 104 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ java |
| 105 | +public interface IGatewayModule { |
| 106 | + |
| 107 | + /** |
| 108 | + * The create method is called by the subclass constructor when the native |
| 109 | + * Gateway creates the Module. The constructor |
| 110 | + * should save both the {@code moduleAddr} and {@code bus} parameters. |
| 111 | + * |
| 112 | + * @param moduleAddr The address of the native module pointer |
| 113 | + * @param bus The {@link MessageBus} to which this Module belongs |
| 114 | + * @param configuration The configuration for this module represented as a JSON |
| 115 | + * string |
| 116 | + */ |
| 117 | + void create(long moduleAddr, MessageBus bus, String configuration); |
| 118 | + |
| 119 | + /** |
| 120 | + * The destroy method is called on a {@link GatewayModule} before it is about |
| 121 | + * to be "destroyed" and removed from the gateway. |
| 122 | + * Once a module is removed from the gateway, it may no longer send or receive |
| 123 | + * messages. |
| 124 | + * |
| 125 | + * The destroy() and receive() methods are guaranteed to not be called |
| 126 | + * simultaneously. |
| 127 | + */ |
| 128 | + void destroy(); |
| 129 | + |
| 130 | + /** |
| 131 | + * The receive method is called on a {@link GatewayModule} whenever it receives |
| 132 | + * a message. |
| 133 | + * |
| 134 | + * The destroy() and receive() methods are guaranteed to not be called |
| 135 | + * simultaneously. |
| 136 | + * |
| 137 | + * @param buffer The message content |
| 138 | + */ |
| 139 | + void receive(byte[] buffer); |
| 140 | +} |
| 141 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 142 | + |
| 143 | +To simplify this, the Azure IoT Gateway SDK provides an abstract `GatewayModule` |
| 144 | +class which implements the `IGatewayModule` interface. Module-implementers |
| 145 | +should extend this abstract class when creating a module. |
| 146 | + |
| 147 | + |
| 148 | + |
| 149 | +Exactly like a standard gateway module written in C, the gateway will handle |
| 150 | +making calls to `Module_Create`, `Module_Receive`, and `Module_Destroy`. These |
| 151 | +three functions are implemented by the **Java Module Host** which handles the |
| 152 | +communication to the gateway module written in Java. Below is a description of |
| 153 | +what the **Java Module Host** will do in each of these cases: |
| 154 | + |
| 155 | +### Module\_Create |
| 156 | + |
| 157 | +When the **Java Module Host**’s `Module_Create` function is invoked by the |
| 158 | +gateway, it: |
| 159 | + |
| 160 | +- Creates a JVM with the provided JVM configuration if this is the first Java |
| 161 | + module added to the gateway. |
| 162 | + |
| 163 | +- Constructs a `MessageBus` Java object using the `MESSAGE_BUS_HANDLE`. |
| 164 | + |
| 165 | +- Finds the module’s class with the name specified by the `args.class_name`, |
| 166 | + invokes the constructor passing in the `MODULE_HANDLE`, `MessageBus` object, |
| 167 | + the JSON args string for that module, and creates the Java module. |
| 168 | + |
| 169 | +- Gets a global reference to the newly created `GatewayModule` object to be saved by |
| 170 | + the `JAVA_MODULE_HOST_HANDLE`. |
| 171 | + |
| 172 | +### Module\_Receive |
| 173 | + |
| 174 | +When the **Java Module Host**’s `Module_Receive` function is invoked by the |
| 175 | +gateway, it: |
| 176 | + |
| 177 | +- Serializes the `MESSAGE_HANDLE` content and properties and invokes the |
| 178 | + `receive` method implemented by the Java module with the `MODULE_HANDLE` and |
| 179 | + the serialized message. |
| 180 | + |
| 181 | +### Module\_Destroy |
| 182 | + |
| 183 | +When the **Java Module Host**’s `Module_Destroy` function is invoked by the |
| 184 | +gateway, it: |
| 185 | + |
| 186 | +- Attaches the current thread to the JVM |
| 187 | + |
| 188 | +- Invokes the `destroy` method implemented by the Java module. |
| 189 | + |
| 190 | +- Deletes the global reference to the Java module object. |
| 191 | + |
| 192 | +- Destroys the JVM if it is the last Java module to be destroyed. |
| 193 | + |
| 194 | +Communication **FROM** the Java module |
| 195 | +-------------------------------------- |
| 196 | + |
| 197 | +As previously mentioned, the **Java Module Host** will only handle communication |
| 198 | +from the native gateway process **to** the Java module. In order to communicate |
| 199 | +**from** the Java module to the native gateway process, the `MessageBus` class |
| 200 | +must be used. The `MessageBus` class provides a method to publish messages onto |
| 201 | +the native Message Bus and loads a dynamic library that implements expected |
| 202 | +functions for publishing onto the native Message Bus. So, the above diagram |
| 203 | +should look a bit more like this: |
| 204 | + |
| 205 | + |
0 commit comments