Docker Container Development
December 17, 2019

Docker Container Development With Visual Studio Code and JMSL

Embedded Analytics

Container-based development has been a rising area of software development. However, despite the flexibility, container development creates its own set of unique challenges.

In this article, we'll look at the first steps in taking advantage of container development when working with JMSL.

Using Docker for Development

One challenge in container development, due to containers not typically having a display, is the lack of a native editor. With a new "Remote - Containers" extension for Visual Studio Code, Microsoft has aimed to alleviate this problem. "Remote - Containers" enable developers to use Visual Studio Code as if it were running inside the Container, allowing for easier project management, development, and debugging.

While each piece of the example below will be explained, if you're new to Docker, Containers, or even Visual Studio Code, it may help to get a better understanding of them before proceeding.

Example: Docker Container Development With JMSL

The example we'll be looking at JMSL with the BesselEx1 example. Additional examples and complete documentation can be found in the documentation.

Requirements

Project Structure

In order to improve integration with Visual Studio Code, Maven will be used to manage our example project's configuration. As a side-effect of this, the folder structure and file names used need to be set up in a particular way:

.
|-- .devcontainer
|   |-- Dockerfile
|   |-- devcontainer.json
|   `-- jmsl-2018.1.0-linux_eval.run
|-- .vscode
|   `-- launch.json
|-- pom.xml
`-- src
    `-- main
        `-- java
            `-- example
                `-- BesselEx1.java


Docker Container Configuration

At the project's root directory the .devcontainer folder allows us to specify how to set up our Docker container along with how Visual Studio Code should use it.

The devcontainer.json file offers Visual Studio Code-specific configurations for how to interact with Docker. It's here that we specify attributes such as Visual Studio Code extensions and Java home. Additionally, in order to simplify our license management, we use the "-v" flag to mount our license file as a volume.

Note: /path/to/imsl_eval.dat must be updated with the appropriate path to your JMSL subscription license file.

/.devcontainer/devcontainer.json

{
    "name": "JMSL Example",
    "dockerFile": "Dockerfile",
    "settings":{
        "java.home": "/docker-java-home",
        "terminal.integrated.shell.linux": "/bin/bash"
    },
    "extensions": [
        "vscjava.vscode-java-pack",
        "redhat.vscode-xml"
    ],
    "runArgs": [
        "-v", "/path/to/imsl_eval.dat:/opt/RogueWave/imsl_eval.dat"
    ]
}


Dockerfile, on the other hand, tells Docker how to build our container. In the file below, we'll set up a new image utilizing Maven 3.6 and JDK 11.

/.devcontainer/Dockerfile

FROM maven:3.6-jdk-11
 
ENV DEBIAN_FRONTEND=noninteractive
 
# Install recommended packages
RUN apt-get update
RUN apt-get -y install --no-install-recommends apt-utils dialog
RUN apt-get -y install git procps lsb-release
 
# Link Java install directory to our previously defined "docker-java-home" folder
RUN ln -s "${JAVA_HOME}" /docker-java-home
 
# Copy and run JMSL installer
ENV JMSL_INSTALLER jmsl-2018.1.0-linux_eval.run
 
COPY ${JMSL_INSTALLER} /tmp/jmsl-installer.run
RUN /tmp/jmsl-installer.run --mode unattended
RUN rm /tmp/jmsl-installer.run
 
ENV DEBIAN_FRONTEND=


Finally, in order to ensure Docker is able to find and run our JMSL installer, we must place the jmsl-2018.1.0-linux_eval.run file in the .devcontainer folder.

Project files

Now that our container is properly configured, we need to set up our Maven project. We do this through the pom.xml file.

/pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>example</groupId>
  <artifactId>jmsl-docker-example</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>jmsl-docker-example</name>
  <url>http://www.roguewave.com/</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>jmsl</groupId>
      <artifactId>jmsl</artifactId>
      <version>2018.1</version>
      <scope>system</scope>
      <systemPath>/opt/RogueWave/jmsl-core-2018.1.0-eval.jar</systemPath>
    </dependency>
  </dependencies>
</project>


While the code of this file is boilerplate, we've added a <dependency> tag to specify where Maven can find our JMSL dependency.

Of course, specifying our project won't do much good without a source file to go along with it.

Here we've taken the BesselEx1 example and placed it into our project. The package name has been modified for the sake of brevity.

/src/main/java/example/BesselEx1.java

package example;
 
import com.imsl.math.*;
 
public class BesselEx1 {
 
    public static void main(String args[]) {
        double x = 10.e0;
        int hiorder = 4;
        //  Exercise some of the Bessel functions with argument 10.0
        double bi[] = Bessel.I(x, hiorder);
        double bj[] = Bessel.J(x, hiorder);
        double bk[] = Bessel.K(x, hiorder);
 
        System.out.println("Order  Bessel.I     Bessel.J     Bessel.K");
        for (int i = 0; i < 4; i++) {
            System.out.printf("  %d   %10.4f %10.4f  %10.4f\n",
                    i, bi[i], bj[i], bk[i]);
        }
    }
}


Visual Studio Code Configuration

At this point, our container and project are defined. The final piece is to add our launch.json  file. This tells Visual Studio Code how it should invoke our application. In this case, we need to include the com.imsl.license.path property for our license file.

/.vscode/launch.json

{
    "configurations": [
        {
            "type": "java",
            "name": "BesselEx1",
            "request": "launch",
            "mainClass": "example.BesselEx1",
            "projectName": "jmsl-docker-example",
            "vmArgs": "-Dcom.imsl.license.path=/opt/RogueWave/imsl_eval.dat"
        }
    ]
}


Executing the Example

Now that all the files are appropriately set up, we can run the example.

  1. Open the project folder in Visual Studio Code.
  2. Press F1 (or press the green button in the bottom left-hand corner) and select the "Remote-Containers: Reopen Folder in Container..." command.
  3. Run the example application by pressing F5.

A terminal view should open and the following output should be produced:

Order  Bessel.I     Bessel.J     Bessel.K
  0    2815.7166    -0.2459      0.0000
  1    2670.9883     0.0435      0.0000
  2    2281.5190     0.2546      0.0000
  3    1758.3807     0.0584      0.0000


Additional Resources and Next Steps

Now that it runs, feel free to try out the other JMSL examples. For further guidance please review the following resources:

Try JMSL for Free

Want to try JMSL on your project? Request a trial today by clicking the button below.