Runtime Environment
Principle
A Runtime Environment is a module nature for defining the set of APIs available to an Application developer on a Kernel. It is built by aggregating a set of Kernel APIs.
Depending on the SDK that you are using, refer to the SDK 6 module nature page or to the SDK 5 module nature page for more information about Runtime Environment module nature.
Building a Runtime Environment is one of the 2 solutions to define the APIs of a Kernel, as described in the section Expose APIs. Having the set of APIs named and versioned in a Runtime Environment allows to maintain, share and document it outside of a specific Kernel implementation.
Once built, a Runtime Environment module contains the following elements:
A JAR file with the whole library of APIs (
.class
files and.java
), used by Application projects to compile Application code;A JAR file with the
kernel.api
file defined in the module (if any), used by Kernel projects to fetch all thekernel.api
files (by transitivity) to expose APIs when building the Firmware and the Virtual Device;A JAR file with the Javadoc of the APIs for documentation.
The following figure shows the overall build flow:
Create a new Runtime Environment Module
A Runtime Environment Gradle project is created with the com.microej.gradle.runtime-environment
plugin.
plugins {
id("com.microej.gradle.runtime-environment") version "1.0.0"
}
A Runtime Environment module project is created with the runtime-api
skeleton.
<info organisation="com.mycompany" module="myruntimeapi" status="integration" revision="1.0.0">
<ea:build organisation="com.is2t.easyant.buildtypes" module="build-runtime-api" revision="4.0.+">
</ea:build>
</info>
Kernel APIs as Dependencies
The Kernel APIs can be declared as dependencies of the module.
For example, the following dependencies declare a Runtime Environment that aggregates all classes, methods and fields
defined by EDC
, KF
, BON
, MicroUI
and BasicTool
Kernel APIs modules.
dependencies {
implementation("com.microej.kernelapi:edc:1.2.0")
api("ej.api:edc:1.3.4")
implementation("com.microej.kernelapi:kf:2.1.0")
api("ej.api:kf:1.5.1")
implementation("com.microej.kernelapi:bon:1.4.0")
api("ej.api:bon:1.4.0")
implementation("com.microej.kernelapi:microui:3.6.0")
api("ej.api:microui:3.6.0")
implementation("com.microej.kernelapi:basictool:1.4.0")
api("ej.library.runtime:basictool:1.7.0")
}
Warning
Unlike SDK 5 (MMM), Kernel API dependencies are not transitively fetched with SDK 6. Therefore, they must be explicitly added.
The Libraries dependencies must be declared with api (as shown in the example above) to be consumable by the Kernel.
Versions of EDC higher than
1.3.5
are not compatible with the creation of a Runtime Environment. To make sure to use version1.3.5
of EDC, use this snippet in yourbuild.gradle.kts
file:configurations { "runtimeClasspath" { resolutionStrategy.force("ej.api:edc:1.3.5") } }
<dependencies>
<dependency org="com.microej.kernelapi" name="edc" rev="1.0.6"/>
<dependency org="com.microej.kernelapi" name="kf" rev="2.0.3"/>
<dependency org="com.microej.kernelapi" name="bon" rev="1.1.1"/>
<dependency org="com.microej.kernelapi" name="microui" rev="3.1.0"/>
<dependency org="com.microej.kernelapi" name="basictool" rev="1.7.0"/>
</dependencies>
The libraries modules are fetched transitively from the Kernel APIs dependencies.
For example, the dependency com.microej.kernelapi#edc;1.0.6
fetches the library ej.api#edc;1.2.3.
It is also possible to force the version of the libraries to use by declaring them as direct dependencies. This is typically used to get a latest version of the library with improvements such as Javadoc fixes or Null Analysis annotations. In this example:
<dependencies>
<dependency org="com.microej.kernelapi" name="edc" rev="1.0.6"/>
<dependency org="ej.api" name="edc" rev="1.3.4"/>
</dependencies>
The Runtime Environment uses the version 1.3.4
of the EDC library instead of the version 1.2.3
fetched transitively by the dependency com.microej.kernelapi#edc;1.0.6
.
Kernel APIs as Project File
The Kernel APIs can also be defined in a file in the Runtime Environment directly.
The file must be named kernel.api
and stored in the src/main/resources
folder.
Add Add-On Processors
Note
This feature is available for SDK 5 only.
When the Runtime Environment includes an Add-On Library which uses an Add-On Processor, this Add-On Processor must be declared as a direct dependency in the Runtime Environment.
The Add-On Processor dependency line can be retrieved as follows:
In your target module repository, go to the Add-On Library folder,
Open the
ivy-[version].xml
file,Search for the dependency line with
conf="addon-processor->addon-processor"
<ivy-module xmlns:ea="http://www.easyant.org" xmlns:ej="https://developer.microej.com" xmlns:m="http://ant.apache.org/ivy/maven" version="2.0" ej:version="2.0.0"> <info organisation="com.mycompany" module="mylibrary" revision="M.m.p" status="release" publication="20220523165033"> ... </info> <configurations> ... <conf name="addon-processor" visibility="public" description="Addon processors dependencies."/> </configurations> <publications> ... </publications> <dependencies> <dependency org="ej.api" name="edc" rev="1.3.3" conf="default->default;provided->provided"/> ... <dependency org="com.mycompany.addon" name="mylibrary-processor" rev="x.y.z" conf="addon-processor->addon-processor"/> ... </dependencies> </ivy-module>
In the Runtime Environment module description file, declare the
addon-processor
configuration in the list ofconfigurations
<conf name="addon-processor" visibility="public" description="Add-On Processors dependencies."/>
Paste the Add-On Processor dependency line
Warning
If the Add-On library version is changed, the Add-On Processor version must be updated.
Here is a list of known libraries using an Add-On Processor:
NLS:
<dependency org="com.microej.tool.addon.runtime" name="binary-nls-processor" rev="<version>" conf="addon-processor->addon-processor"/>
-
<dependency org="ej.tool.addon.wadapps" name="wadapps-processor" rev="<version>" conf="addon-processor->addon-processor"/>
-
<dependency org="com.microej.tool.addon.runtime" name="js-processor" rev="<version>" conf="addon-processor->addon-processor"/>
Use a Runtime Environment in an Application
The Runtime Environment dependency must be declared in the Application project as following:
For an Application:
microejRuntimeEnvironment("com.mycompany:myruntime-environment:1.0.0")
For a Kernel Application:
implementation("com.mycompany:myruntime-environment:1.0.0")
<dependency org="com.mycompany" name="myruntime-environment" rev="1.0.0" conf="provided->runtimeapi"/>
Note
If you want to add an other library dependency, make sure it is has been built on this Runtime Environment. Otherwise this could lead to inconsistent situations, for example by using an API not available at runtime. An other approach is to add it to the Runtime Environment.
Extend a Runtime Environment
Note
This feature is available for SDK 5 only.
In a Kernel, Foundation and Add-On libraries can be extended by adding new methods to their existing classes. For example, it allows to add new methods to the class java.lang.String of the module ej.api#edc. This is done thanks to the Class Extender tool. This tool works at binary level and is able to inject methods from one class to another. Extensions can thus be independently compiled and be retrieved by the Kernel and applied during a Multi-Sandbox Executable build.
To make the extensions available to Application developers, the Runtime Environment has to be extended too.
The following diagram illustrates the process of extending the default java.lang.String class from [EDC] from a Kernel developer point of view:
The extension must be applied in 2 locations:
In the Runtime Environment. This ensures that Applications developers can see and use the new methods. The custom Runtime Environment must contain the following element:
the API to extend, as a dependency. Here this is the EDC Foundation Library API, which contains the java.lang.String class we want to extend. We can add it transitively through its kernelapi:
<dependency org="com.microej.kernelapi" name="edc" rev="1.0.6"/>a Kernel API file definition in the
src/main/resources
folder which includes the new methods. For example:<?xml version="1.0" encoding="UTF-8"?> <require> <method name="java.lang.String.myNewMethod(int)java.lang.String"/> <method name="java.lang.String.myOtherNewMethod()void"/> </require>the new version of the Java source of the API to extend. This class overrides the original class fetched from the dependency. Therefore it must include all the methods, the ones existing in the original class as well as the new methods, with their Javadoc specification. In our example, we must add a new
String.java
source file in thesrc/main/java/java/lang
folder, and add the new methods:public String myNewMethod(int number) { return "My number is " + number; } public void myOtherNewMethod() { System.out.println("Hello!"); }This class overrides the java.lang.String class fetched from the EDC dependency.
Once built, the custom Runtime Environment contains the new methods and can be used in the Applications projects.
In the Kernel. The EDC implementation is extended during the Kernel build thanks to the Class Extender tool. Refer to the Class Extender tool README and especially to the chapter
Include Class Extender During Firmware Project Build
to learn how to integrate it in a Kernel build.MicroEJ Corp. provides some ready-to-use extension modules:
com.microej.library.runtime#string-regex: String methods based on Regular Expressions (e.g.
String.split()
,String.replaceAll()
)com.microej.library.runtime#string-format: String formatting utility methods (e.g.
String.format()
)