Mock¶
Principle¶
The HIL engine is a Java standard-based engine that runs Mocks. A Mock is a jar file containing some Java classes that simulate natives for the Simulator. Mocks allow applications to be run unchanged in the Virtual Device while still appearing to interact with native code.
Functional Description¶
As with SNI, HIL is responsible for finding the method to execute as a replacement for the native Java method that the MicroEJ Simulator tries to run. Following the SNI specification philosophy, the matching algorithm uses a naming convention. When a native method is called in the MicroEJ Simulator, it requests that the HIL engine execute it. The corresponding Mock executes the method and provides the result back to the MicroEJ Simulator.

The MicroEJ Simulator Executes a Native Java Method foo()
.¶
Example¶
package example;
import java.io.IOException;
/**
* Abstract class providing a native method to access sensor value.
* This method will be executed out of virtual machine.
*/
public abstract class Sensor {
public static final int ERROR = -1;
public int getValue() throws IOException {
int sensorID = getSensorID();
int value = getSensorValue(sensorID);
if (value == ERROR) {
throw new IOException("Unsupported sensor");
}
return value;
}
protected abstract int getSensorID();
public static native int getSensorValue(int sensorID);
}
class Potentiometer extends Sensor {
protected int getSensorID() {
return Constants.POTENTIOMETER_ID; // POTENTIOMETER_ID is a static final
}
}
To implement the native method getSensorValue(int sensorID)
, you
need to create a MicroEJ mock project containing the same Sensor
class on the same example
package.
To create a new MicroEJ mock project:
- Select File > New > Module Project,
- Fill the module information (project name, module organization, name and revision),
- Select the microej-mock skeleton,
- Click on Finish.
The following code is the required Sensor
class of the created Mock
project:
package example;
import java.util.Random;
/**
* Java standard class included in a Mock jar file.
* It implements the native method using a Java method.
*/
public class Sensor {
/**
* Constants
*/
private static final int SENSOR_ERROR = -1;
private static final int POTENTIOMETER_ID = 3;
private static final Random RANDOM = new Random();
/**
* Implementation of native method "getSensorValue()"
*
* @param sensorID Sensor ID
* @return Simulated sensor value
*/
public static int getSensorValue(int sensorID) {
if( sensorID == POTENTIOMETER_ID ) {
// For the simulation, Mock returns a random value
return RANDOM.nextInt();
}
return SENSOR_ERROR;
}
}
Note
The visibility of the native method implemented in the mock must be public
regardless of the visibility of the native method in the application. Otherwise the following exception is raised: java.lang.UnsatisfiedLinkError: No such method in remote class
.
Mocks Design Support¶
Interface¶
The MicroEJ Simulator interface is defined by static methods on the Java
class com.is2t.hil.NativeInterface
.
Array Type Arguments¶
Both [SNI] and HIL allow arguments that are arrays of base types. By default the contents of an array are NOT sent over to the Mock. An “empty copy” is sent by the HIL engine, and the contents of the array must be explicitly fetched by the Mock. The array within the Mock can be modified using a regular assignment. Then to apply these changes in the MicroEJ Simulator, the modifications must be flushed back. There are two methods provided to support fetch and flush between the MicroEJ Simulator and the HIL:
refreshContent
: initializes the array argument from the contents of its MicroEJ Simulator counterpart.flushContent
: propagates (to the MicroEJ Simulator) the contents of the array that is used within the HIL engine.

An Array and Its Counterpart in the HIL Engine.¶
Below is a typical usage.
public static void foo(char[] chars, int offset, int length){
NativeInterface ni = HIL.getInstance();
//inside the Mock
ni.refreshContent(chars, offset, length);
chars[offset] = 'A';
ni.flushContent(chars, offset, 1);
}
Blocking Native Methods¶
Some native methods block until an event has arrived [SNI]. Such behavior is implemented in native using the following three functions:
int32_t SNI_suspendCurrentJavaThread(int64_t timeout)
int32_t SNI_getCurrentJavaThreadID(void)
int32_t SNI_resumeJavaThread(int32_t id)
This behavior is implemented in a Mock using the following methods on a lock
object:
- Object.wait(long timeout): Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.
- Object.notifyAll(): Wakes up all the threads that are waiting on this object’s monitor.
NativeInterface.notifySuspendStart()
: Notifies the Simulator that the current native is suspended so it can schedule a thread with a lower priority.NativeInterface.notifySuspendEnd()
: Notifies the Simulator that the current native is no more suspended. Lower priority threads in the Simulator will not be scheduled anymore.
public static byte[] data = new byte[BUFFER_SIZE];
public static int dataLength = 0;
private static Object lock = new Object();
// Mock native method
public static void waitForData() {
NativeInterface ni = HIL.getInstance();
// inside the Mock
// wait until the data is received
synchronized (lock) {
while (dataLength == 0) {
try {
ni.notifySuspendStart();
lock.wait(); // equivalent to lock.wait(0)
} catch (InterruptedException e) {
// Use the error code specific to your library
throw new NativeException(-1, "InterruptedException", e);
} finally {
ni.notifySuspendEnd();
}
}
}
}
// Mock data reader thread
public static void notifyDataReception() {
synchronized (lock) {
dataLength = readFromInputStream(data);
lock.notifyAll();
}
}
Resource Management¶
In Java, every class can play the role of a small read-only file system root: The stored files are called “Java resources” and are accessible using a path as a String.
The MicroEJ Simulator interface allows the retrieval of any resource
from the original Java world, using the getResourceContent
method.
public static void bar(byte[] path, int offset, int length) {
NativeInterface ni = HIL.getInstance();
ni.refreshContent(path, offset, length);
String pathStr = new String(path, offset, length);
byte[] data = ni.getResourceContent(pathStr);
...
}
Synchronous Terminations¶
To terminate the whole simulation (MicroEJ Simulator and HIL), use the stop() method.
public static void windowClosed() {
HIL.getInstance().stop();
}
Dependencies¶
The HIL Engine API is automatically provided by the microej-mock
project skeleton.
Installation¶
First create a new module project using the microej-mock
skeleton.

Once implemented, right-click on the repository project and select Build Module
.
Once the module is built, the mock can be installed in a Platform in one of the two ways:
- by adding the mock module as a regular Platform module dependency (if your Platform configuration project contains a
module.ivy
file), - or by manually copying the JAR file
[mock_project]\target~\rip\mocks\[mock_name].jar
to the Platform configuration mock dropins folderdropins/mocks/dropins/
.
Make sure the option Resolve Foundation Libraries in Workspace is enabled to use the mock without having to install it after each modification during development.
Use¶
Once installed, a Mock is used automatically by the Simulator when the MicroEJ Application calls a native method which is implemented into the Mock.
JavaFX¶
JavaFX is an open-source library for creating modern Java user interfaces that is highly portable. It can be used to quickly create graphical Mocks for your Platform.
- If your SDK is running on JDK 8, the Oracle JDK contains JavaFX, so this version allows you to use it right now in your project.
- If your SDK is running on JDK 11, JavaFX must be added as an additional dependency to your Mock and Platform project. For that, MicroEJ Corp. provides a ready-to-use packaged module for all supported OS versions.
<dependency org="com.microej.tool" name="javafx" rev="1.2.0" />
The Module serves two purposes, depending on whether it is added to a Mock or a Platform project:
- In a Mock project, JavaFX is added as a compile-time dependency, its content is not included in the Mock.
- If your Platform contains at least one Mock, JavaFX must be added to the Platform project in order to embed its content in the Platform.