Java Install and Build
This topic outlines how to install and build the initial support for Java provided in Legato release 16.04.
Download JVM
Go to http://www.oracle.com/technetwork/java/embedded/embedded-se/downloads/index.html Dowload the Oracle bundle suitable for your target, and extract it. Use either compact1 or compact2 profile in the linux_arm_sflt sub-folder
Environment Variables
Before you can build Java support in Legato, your shell needs to be setup with the environment variable JAVA_INCLUDE_DIR
On Ubuntu 15.10 and later, set:
JAVA_INCLUDE_DIR=/usr/lib/jvm/java-8-openjdk-amd64/
On earlier Ubuntu versions, set:
JAVA_INCLUDE_DIR=/usr/lib/jvm/java-7-openjdk-amd64/
Then set the Oracle's embedded JVM environment variable EJDK_DIR
to the directory where you installed the built JVM compact profile.
Java Program Structure
Java components have Java code instead of C or C++ code.
You create a javaPackage:
section in the @ .cdef listing Java packages to build. It should look something like this:
javaPackage:{io.legato.samples}
The build tools will look for Java to code under COMPONENT_DIR/src/io/legato/samples/*
.java
It won't recurse automatically into subdirectories; if you want subdirectories, they also must added to the JavaPackage section.
javaPackage:{io.legato.samplesio.legato.samples.fooio.legato.samples.bar}
The first Java package listed is assumed to be the main component package as it contains a class with the same name of the component, and it implements the interface (io.legato.Component
).
A hello world Java app folder structure should look something like this:
+-- javaHelloComponent| +-- Component.cdef| +-- src| +-- io| +-- legato| +-- samples| +-- javaHelloComponent.java+-- jHello.adef
Bundling JVM and Apps into Components
You need to bundle the app with your specific embedded JVM; otherwise, the JVM won't be automatically linked into your app.
You do this by creating entries in the Java component's requires: section.
In this sample:
embeddedOracleJvm
bundles Oracle's JVM into an apponTargetOracleJvm
assumes the JVM has already been installed on the target and binds it into the component:
javaPackage:{io.legato.samples}requires:{component:{embeddedOracleJvm// onTargetOracleJvm}}
The .adef files don't have specific changes to support a Java app. The class path and execute configuration are automatically setup when Java components are used.
- Note
- Don't mix C/C++ and Java components in the same executable, although this may be supported in a later release.
Java Target Structure
Everything needed to run Java on the target goes into the working directory the same as C/C++ apps. However, Java requires that a src
directory exsits where the generated code is placed in the component working directory.
The component factory code is generated as io.legato.generated.component
.<componentName>.Factory
The class files are placed into the corresponding obj
directory. A static main is generated in a class named Main
under the apps directory called io.legato.generated.exe.helloWorld.Main
Like components, Java code goes under an obj
directory. The component jar
file is created under the staging read-only directory. The component for the executable is created under the staging directory. The executable's main .jar file is staged under the app's bin directory, and the component
.jar files are staged under lib for final app packaging.
Component Structure
The build system expects a "main class" inside of the first package listed in a javaPackages section.
The main class is expected to have the same name as the component and to implement the interface io.legato.Component.
The two methods to be implemented from that interface are:
public interface Component{public void componentInit();public void setLogger(Logger logger);}
An instance of the connection to the Legato log is passed to the component through . The method componentInit
is called once the framework has initialized, all client interface connections have been established, and all server interfaces have been advertised.
A component main looks like this:
package my.package.namespace;import io.legato.Ref;import io.legato.Level;import io.legato.Result;import io.legato.Component;import java.util.logging.Logger;public class MyComponent implements Component{private Logger logger;public MyComponent(){}public void componentInit(){logger.Log(Level.INFO, "Hello world.");}public void setLogger(Logger newLogger){logger = newLogger;}}
Legato API Generation
When you include an API in your Java component's requires:
section, an interface and client class are generated for that API.
For example, we could import the config API like this:
requires:{api:{Config = le_cfg.api}}
An interface named Config will then be generated in the package io.legato.api. The framework will then expect the component main class to have a method with the following signature:
public void setConfig(Config newCfg){cfg = newCfg;}
Where cfg
can be a member variable of the class to hold the client instance for the config API.
The API reference types, enumerations, and constants, and event interfaces are generated as members of the interface class Config.
For example, to read a message from the config:
Config.IteratorRef ref = cfg.CreateReadTxn("");Ref<String> messageRef = new Ref<String>(new String());Result code = config.GetString(ref, "/myDataa/message", messageRef, "Default Message");if (code != Result.OVERFLOW){logger.log(Level.INFO, "Message: " + messageRef.getValue());}else{logger.log(Level.WARN, "Message overflow.");}
- Note
- All API function OUT parameters need to be wrapped in a Ref.
When providing a service from a Java component, you simply need to implement the interface and its methods.
Dependency Checking
Like C/C++ components, the ninja build tool is used to do dependency checking to compile and package an app. If the .class files are up to date against the .java sources, then Java code compiling won't occur. The build tools also assume that the javac
command line compiler is somewhere in the path.
Copyright (C) Sierra Wireless Inc. Use of this work is subject to license.