Sunday, July 14, 2019

Robo4J: Adafruit LED Backpacks - guide

Img.1.: Robo4J with Adafruit LED Backpacks
  In the following blog post I will describe how to use the Adafruit LED Backpacks together with Robo4J framework. All mentioned examples are running on Java11+ and as you will see, they are very easy to implement, modify and connect with even more advanced systems.

Inspired by a motto : Plug&Play.  

It's a lot of fun to have all those LEDs under the control and due to Robo4J you don't have to use C++ example, just a pure Java ... 

  The Adafruit is quite great company,  they do provide a lot of easy to implement breakout boards for RaspberryPi platform. One of them are LED Backpacks
  Robo4J does contain  implementations for Bargraphs, Matrixes and Alphanumeric ones. The agenda: 
  1. Bi-Color 24 Bargraph
  2. Bi-Color 8x8 Matrix
  3. 0.54" Alphanumeric
To assemble any of backpacks I'd recommend to go through the well described manuals on the official Adafruit web pages

example requirements:
1. RaspberryPi3 B+ 
2. Java 11 (example: Bell-Soft Liberica 11+)
3. one of Adafruit LED Backpack 

  Before we enjoy a LED shows, let's take a quick look how all is bundled. It should give you an idea how to connect LEDs in other than discussed cases. 
  As you know Robo4J is a light weight messaging framework. It's separated to the dedicated modules according to the purpose. In following blog post we do use robo4j-core, robo4j-units-rpi and robo4j-hw-rpi as you can see in the diagram bellow. The all three mentioned I2C examples are by default configured as following: 


int bus = I2CBus.BUS_1;
int address =  0x70;\

Important: If you intent to use only the robo4j-hw-rpi, it means only the hardware, the module can be used alone without any additional dependencies.
Img.2.: Robo4J Adafruit backpack schema

Let's suppose we have all assembled and we start with the 1st Bi-Color 24 Bargraph.

1. Bi-Color 24 Bargraph
Img.3.: Bi-Color24 Bargraph example
We have connected the device over the I2C interface to the RaspberryPi according to the Adafruit Documentation. As the first step we test the hardware, let's create a simple example that uses only the robo4j-hw-rpi module. :


public class BiColor24BargraphExample {
  public static void main(String[] args) throws Exception {
    BiColor24BarDevice device = new BiColor24BarDevice();
device.clear();
device.display();

int counter = 0;

while(counter < 3){
  for (int i=0; i<12; i++){
    int colorNumber = (i+counter) % 3 + 1;
    XYElement element = new XYElement(i, BiColor.getByValue(colorNumber));
    device.addBar(element);
    TimeUnit.MILLISECONDS.sleep(200);
    device.display();
  }
  counter++;
}
  }
}
The code above (Img.1.) shows how the elements are created and send to the Robo4j hardware unit. 
The next example snippet shows how the Robo4J hardware is exposed to the units from robo4j-units-rpi module. The following module offers more advanced features upon the hardware, like command or continual operations, which allows more advanced usages.


RoboContext ctx = new RoboBuilder().add(settings).build();
ctx.start();
RoboReference<LEDBackpackMessage> barUnit = ctx.getReference("bargraph");
LEDBackpackMessage<XYElement> clearMessage = new LEDBackpackMessage<>();
AtomicInteger position = new AtomicInteger();
executor.scheduleAtFixedRate(() -> {
  if (position.get() > BiColor24BarDevice.MAX_BARS - 1) {
    position.set(0);
  }
  barUnit.sendMessage(clearMessage);
  XYElement element = new XYElement(
    position.getAndIncrement(),
    BiColor.getByValue(position.get() % 3 + 1));
  LEDBackpackMessage<XYElement> addMessage = new LEDBackpackMessage<>(LEDBackpackMessageType.DISPLAY);
  addMessage.addElement(element);
  barUnit.sendMessage(addMessage);


}, 2, 1, TimeUnit.SECONDS);

Congratulation the 1.st LED Backpack is in use and running! 

2.Bi-Color 8x8 Matrix
Img.4.: Bi-Color 8x8 Matrix Face example
The 2nd example is Bi-Color 8x8 LED Matrix. It is really a lot of fun as you can display a simple images or animations. The Matrix is provided exactly in the same manner as the previous example. The hardware can be use only by robo4j-hw-rpi module to make hardware testing simpler, quicker and more fun ;). Here is the simple code snippet:


char[] faceSmile = "00333300,03000030,30300303,30000003,
    30300303,30033003,03000030,00333300".toCharArray();
...
List<char[]> availableFaces = Arrays.asList(faceSad, faceNeutral, faceSmile);
for (char[] face : availableFaces) {
  matrix.clear();
  matrix.display();
  byte[] faceByte = LEDBackpackUtils.createMatrixBiColorArrayByCharSequence(
    matrix.getMatrixSize(), ',',face);
    XYElement[] faceElements = LEDBackpackUtils.createMatrixByBiColorByteArray(matrix.getMatrixSize(), faceByte);
    matrix.addPixels(faceElements);
    matrix.display();
    TimeUnit.SECONDS.sleep(1);
}
  
Having the hardware tested we can move the the robo4j-units-rpi module and enjoy a bit advanced hardware usages. Now we have an opportunity to connect the units with another ones and create a more advanced system based on messages passing, see a example snippet bellow:


RoboContext ctx = new RoboBuilder().add(settings).build();
ctx.start();
RoboReference<LEDBackpackMessage> barUnit = ctx.getReference("matrix");
LEDBackpackMessage<XYElement> clearMessage = new LEDBackpackMessage<>();
AtomicInteger position = new AtomicInteger();
executor.scheduleAtFixedRate(() -> {
   if (position.get() > 7) {
   position.set(0); }
  barUnit.sendMessage(clearMessage);
  XYElement element = new XYElement(
    position.get(), position.getAndIncrement(),
    BiColor.getByValue(position.get() % 3 + 1));
    LEDBackpackMessage<XYElement> addMessage = 
        new LEDBackpackMessage<>(LEDBackpackMessageType.DISPLAY);
    addMessage.addElement(element);
    barUnit.sendMessage(addMessage);

}, 2, 1, TimeUnit.SECONDS);


3. 0.54" Alphanumeric
Img.5.: Adafruit Alphanumeric LED Backpack
 The previous examples were only about to just turning on/off a specific LED diodes. The last example shows how to display ASCII Characters on 14-segments (Img.6.) display (see wiki). The value can be transmitted as the ASCII character of specific segments can be turned off/on as is visible from the picture above (Img.5.). 
Img.6.: 14-segments LED (source: Adafruit)
The robo4j-hw-rpi module provides an example that shows how to configure and run Adafruit hardware:

AlphanumericDevice device = new AlphanumericDevice();
device.clear();
device.display();
device.addCharacter('R', false);
device.addCharacter('O', true);
device.addCharacter('B', false);
device.addByteValue((short) 0x3FFF, true);
device.display();

It looks very simple. It's possible to add the value by the character reference on by its 16-bit value. The module robo4j-units-rpi, similar as in previous cases, provides a advanced features that can be used for controlling the Alphanumeric LED Backpack, see the code bellow: 

RoboContext ctx = new RoboBuilder().add(settings).build();
ctx.start();
RoboReference<LEDBackpackMessage> alphaUnit = ctx.getReference("alphanumeric");
LEDBackpackMessage<AsciElement> clearMessage = new LEDBackpackMessage<>();
LEDBackpackMessage<AsciElement> displayMessage = new LEDBackpackMessage<>(LEDBackpackMessageType.DISPLAY);
AtomicInteger textPosition = new AtomicInteger();
executor.scheduleAtFixedRate(() -> {
    if(textPosition.getAndIncrement() >= MESSAGE.length - 1){
        textPosition.set(0);
    }
    alphaUnit.sendMessage(clearMessage);
    LEDBackpackMessage<AsciElement> messageAdd = new LEDBackpackMessage<>(LEDBackpackMessageType.ADD);
    char currentChar =  MESSAGE[textPosition.get()];
    adjustBuffer(currentChar);
    messageAdd.addElement(new AsciElement(0, BUFFER[0], false));
    messageAdd.addElement(new AsciElement(1, BUFFER[1], false));
    messageAdd.addElement(new AsciElement(2, BUFFER[2], false));
    messageAdd.addElement(new AsciElement(3, BUFFER[3], false));
    alphaUnit.sendMessage(messageAdd);
    alphaUnit.sendMessage(displayMessage);
}, 1, 500, TimeUnit.MILLISECONDS);

The final words and conclusion
 The Robo4j framework delivers easy to use hardware abstractions. Such abstractions are exposed through the Robo4j units. The Units provide an additional functionalities (example: simple matrix operation, bargraph led selection etc.) The Robo4j Units allow to employ scheduled or time based operations. All units can be extended about any features/possibilities provided by the Java Ecosystem. 

The Robo4j Adafruit LED Backpack implementation gives a power to create any LED show.
Enjoy and Happy Coding ! 

Thursday, March 7, 2019

Build a distributed system with Hardware and SpringBoot using Robo4J framework on Java 11

Img.0: Robo4J Application running on RaspberryPi with Java 11

Following post is specially dedicated to all Spring framework fans and others :). It looks nowadays that basic knowledge of spring framework is necessary in the Java field. 

I recently asked random attendee at the meetup a question: "... how good do you feel with Java language?". He started his answer with a long Spring story about how good he is in developing and "hacking" Spring using various libraries, streams, message queues etc. ... I don't even remember all technologies he listed.  
  In his answer is also one important point. People know and are able to develop some apps with the Spring framework. This also means that if any new framework wants to be used by a bit wider dev. community it should follow the main stream. 
The Spring Framework is inside such main stream. It provides quite easy way how to prototype and use the latest technologies. Companies are putting some effort here ! :)

1. Wiring up Robo4J and Spring Contexts 
Img.1: Spring Framework and Robo4J Framework runtimes

For quite a long Robo4J didn't have it's own spring-plugin. The upcoming version is coming up with "
robo4j-spring-configuration-starter" plugin. The plugin allows to expose the RoboContext to the spring ApplicationContext. 
It means Robo4J context can be easily injected into the appropriated Spring managed component ( @Component, @Service or @Configuration ). The both contexts Spring and Robo4J are separated from each other (see Img.1).
When the robo4j configuration starter plugin has been added to the application classpath it tries to search by default for the descriptor files "robo4jSystem.xml" and "robo4jContext.xml". 
The "robo4jContext.xml" file is mandatory by default
When the file is not present in resources directory the Robo4j exception will be thrown. 
It doesn't make sense to continue without having anything to wire. 

The starter plugin can be added to the build system descriptor file, for example Gradle: 

...
dependencies {
   implementation "com.robo4j:robo4j-spring-configuration-starter"
   implementation "com.robo4j:robo4j-core"
   implementation "com.robo4j:robo4j-hw-rpi"
   implementation "com.robo4j:robo4j-units-rpi"
   implementation "org.springframework.boot:spring-boot-starter"
   implementation "org.springframework.boot:spring-boot-starter-web"
    ...
}
...

2. Starting Robo4J and Spring together
Having a robo4j starter plugin present together with robo4j context descriptor file ("robo4jContext.xml") we are ready to start the Spring application. The plugin will automatically configure appropriate bean. Following output can be observed in the log file:

: Initializing Spring embedded WebApplicationContext
: Root WebApplicationContext: initialization completed in 1024 ms
: Robo4J context will be initiated
: Initializing ExecutorService 'applicationTaskExecutor'
: Tomcat started on port(s): 8080 (http) with context path ''

The log snippet shows that Robo4J context will be initiated, which means all relevant hardware units and units will be configured and started. 

3. Building up distributed system with hardware 
Following section describes how to build a simple distributed system. The distributed system consists from two parts: Robo4J Spring application and pure Robo4J application. The both applications are configured over Robo4J auto-discovery mechanism. The auto discovery mechanism allows automatic Robo4J units configuration but more details are over the scope of this article (see Img.2.)
Img.2.: Example distributed application using Robo4J & Spring with auto-discovery mechanism
3a. Robo4J Spring application 
The Img.2. shows how the spring application has the access to the Rob4J context. The Robo4J context is instantiated and configured by the starter plugin. The rest of spring application is just standard, we create one @RestController and @Service. 

@RestController
public class MessageRestController {

    private final LcdService lcdService;

    @Autowired
    public MessageRestController(LcdService lcdService) {
        this.lcdService = lcdService;
    }

    /**
     * Hello world get
     *
     * @return default message
     */
    @GetMapping("/")
    public String index() {
        return "Hello Robo4J Spring World!";
    }

    /**
     * POST end-point for sending message to the Robo4J context
     *
     * @param message simple DTO object
     * @return message content
     */
    @PostMapping("/lcd")
    public String sendMessage(@RequestBody SimpleMessage message) {
        return lcdService.displayMessage(message);
    }
}

The LcdService provides the access to the Robo4J context and propagates the message deeper to the Robo4J context. Inside the RoboContext is found the appropriate unit (example: RemoteLcdUnit). The unit contains the method that sends the message to the remote Robo4J system over the TCP/IP through the Robo4J Unit.

public class RemoteLcdUnit extends RoboUnit<LcdMessage> {
...
    @Override
    public void onMessage(LcdMessage message) {
        RoboContext discoveredContext = LookupServiceProvider
                    .getDefaultLookupService()
                    .getContext(remoteContext);
        if (discoveredContext != null) {
            discoveredContext
                .getReference(unitName)
                .sendMessage(message);
        }
    }
...
}

3b. Robo4J Application
The remote Robo4J application receives the message, deserializes it and sends it to the consumer unit (AdafruitLcdUnit). This unit is registered inside the Robo4J context. 
The application context descriptor ("robo4jContext.xml") looks very simple as the rest is managed by the framework itself.
See the descriptor file:

<robo4j>
    <roboUnit id="lcd">
        <class>com.robo4j.units.rpi.lcd.AdafruitLcdUnit</class>
        <config name="com.robo4j.root">
            <value name="bus" type="int">1</value>
            <value name="address" type="int">0x20</value>
        </config>
    </roboUnit>
</robo4j>

It uses the hardware abstraction provided by the "robo4J-units-rpi" module. 

4. Running both Applications
We have prepared both parts of our simple distributed system. Let's run them. 
Both of them are using OpenJDK 11! In case of RaspberryPi it's the Liberica JDK 11.0.2. 
The Img.2. shows that the communication with the LCD Hardware is possible through Spring @RestController. The RestController provides the POST method, that accepts JSON format of the SimpleMessage class. 

url: POST http://localhost:8080/lcd
body: {"content" : "Java 11, Robo4J \n SpringBoot"}

5. Conclusion
The described example shows how simple it is to build up and run the distributed system using the real hardware units on pure Java. 
The Robo4J Framework allows a simple connection with the Spring kind of applications. It is not necessary to write any line of code in other than JVM language (Java, Kotlin, Scala, JRuby ;). It is also not necessary to use some difficult data transformations written in C in order to put the sensors outputs on the various message queues. 
Robo4J allows to build an event driven systems that are communicating between them selves by passing messages. 
The example additionally shows that  the final system may be distributed over many different JVMs and Robo4J framework takes care about the communication under the hood. This allows to be fully concentrated on the system logic development. 

The following approach supports, nowadays often discussed, "evolutionary architecture" one, which goal is to propose the way how to utilize a different kind of design patterns and desired technologies. 

Happy Coding!

Wednesday, January 23, 2019

Installing Liberica JDK 11.0.2 JDK on RaspberryPi 3+

A few days ago BellSoft announced that Liberica JDK 11.0.2 is available to download. I was so excited to install it on one of my RaspberryPi3+. Sadly there is still no 64-bit Debian version for RPI, so I have to stay with 32-bit one. 

How to install Java on RapsberryPi has been described in more details on our main Robo4J blog. I've followed exactly those steps only with the archive name changed.
$ sudo tar zxvf bellsoft-jdk11.0.2-linux-arm32-vfp-hflt.tar.gz -C /opt

Another way to install Liberica is to download deb package and install it by using apt-get. 
This is probably the better way as you get properly mapped all other JDK features, like JFR.


$ wget https://github.com/bell-sw/Liberica/releases/download/11.0.2/bellsoft-jdk11.0.2-linux-arm32-vfp-hflt.deb

and then: 


$ sudo apt-get install ./bellsoft-jdk11.0.2-linux-arm32-vfp-hflt.deb

As a next step I set a Java 11.0.2 as the default distribution by the following commands:
$ sudo update-alternatives --config javac
$ sudo update-alternatives --config java

Let's test the version by typing:
$ java -version

openjdk version "11.0.2-BellSoft" 2018-10-16
OpenJDK Runtime Environment (build 11.0.2-BellSoft+7)
OpenJDK Server VM (build 11.0.2-BellSoft+7, mixed mode)

Enjoy Coding!

Sunday, January 20, 2019

Installing COBOL on Mac and running "hello Cobol!" program

It may sound a bit crazy, due to my main focus but yes, the title is correct. It does contain word COBOL. Actually the acronym is pretty nice, it means "Common Business-Oriented Language" = COBOL. According to resources COBOL was the 1st popular language designed to be operating system agnostic. It is imperative, procedural language. Oh, It's fair to mention that since 2002 it's also Object-Oriented but I may touch this in one of future post. This short post is more focused on how to run COBOL on a Mac. 

Why COBOL ? True is that my 1st touch with COBOL was at SUN Microsystem in around 2004 or 2005. I don't exactly remember but it was due to some Bank system project. Yes, Cobol is even nowadays widely used in Government, Banks or Industrial systems. Maybe not so much on mainframes but ;) they are still there too. COBOL is used in many legacy applications such as batch and transaction processing jobs. Actually you may be surprised how JVM helps to run COBOL programs, but this is out of the scope of this short post.

1. Installing a COBOL compiler on MAC Mojave. 
I'll use the homebrew (The missing package manager for the macOS). Open your terminal and type:


$ brew install gnu-cobol  

2. Writing the 1st COBOL Program
I'm using VIM on Mac. Sure when you are on Windows or Linux machine you have a possibility to use Visual COBOL for Eclipse from MicroFocus which has a lot more features, or maybe others but I'm familiar with this one. For this post purposes the VIM is more than enough. 
Open the terminal create a "hello_cobol.cob" file with the following content:
$ vi hello_cobol.cob

--- hello_cobol.cob ---
program-id. hello_cobol.

data division.
working-storage section.
01 HELLO_MESSAGE PIC X(12) VALUE "Hello COBOL!".

procedure division.
        display HELLO_MESSAGE.
        goback.


end program hello_cobol.
---

3. Compiling and running the program
As you can see code is very nicely separated into the sections. To get more information about the code structure see for example following guide. To compile a code executed the following command:


$ cobc -free -x hello_cobol.cob

After the successful execution the hello_cobol file is created. This file contains the compiled code and we can run it by: 


$ ./hello_cobol
Output: 
Hello COBOL!

Conclusion: 
Cobol is pretty imperative, procedural language it can be a lot fun.  As a Java programer you may don't want to forget that the parameters in COBOL are mostly passed by the references not by values. Java does manipulated object by references, and all object variables are references but Java doesn't not pass arguments by references, Java passes them by value!
Keep Coding!

Short review of Java 11: Launch Robo4J Single-File Source Code Programs

 Java 11 is available quite long , hmm long, what does it mean ? According to the old release model, it has not even passed warmup phase. I mean maybe not everyone got familiar with all changes included in this release yet, or there was not simply enough time to align it with the process. 
  Well doesn't matter , reality is reality and Oracle has kind of "clearly" announced the conditions and statements. There should not be any surprises. 

  Let's do a short review of the one specific feature before we move to the Java 12 GA. I know there has been done already many blog posts around but we are fully migrating Robo4J to Java 11 and above. I got a feeling it does make a sense to show one on Robo4J project. Let's start.

Launch Single-File Source-Code Programs 
As java has been for long time criticized for kind of obscurity that is necessary to run even a simple program. The JEP-330 serves a solution to this problem. 

Instead of typing and running following lines inside the command line: 
$ javac -classpath libs/*:. SingleFileRobo4j.java
$ java -classpath  libs/*:.  SingleFileRobo4j.java

You do things just simple a it should be 
$ java -classpath libs/*:. SingleFileRobo4j.java

When such command gets executed the following output is printed out:
RoboSystem state Started
================================================
    httpServer                        Started


...Press Key to stop


The ability of running a java single file is simply amazing! It allows you to prototype a robot by using only installed OpenJDK and a command line.

The Robo4J framework provides the ability to define and configure all units by using the descriptor file. See following example:
<robo4j>
    <roboUnit id="httpServer">
        <class>com.robo4j.socket.http.units.HttpServerUnit</class>
        <config name="com.robo4j.root">
            <value name="port" type="int">9022</value>
            <value name="packages" type="String">com.robo4j.socket.http.codec</value>
        </config>
    </roboUnit>
</robo4j>

The descriptor file does contain currently one unit. Having a descriptor XML file defined we need to write shore code to let it execute it by the Robo4J.  Let's create a file SingleFileRobo4j.java with the following content: 


import com.robo4j.RoboBuilder;
import com.robo4j.RoboContext;
import com.robo4j.util.SystemUtil;
import java.io.InputStream;

public class SingleFileRobo4j {

    public static void main(String[] args) throws Exception {
        InputStream contextIS = SingleFileRobo4j.class.getClassLoader().getResourceAsStream("robo4j.xml");
        RoboContext system = new RoboBuilder().add(contextIS).build();
        system.start();
        System.out.println(SystemUtil.printStateReport(system));
        System.out.println("...Press Key to stop");
        System.in.read();
        system.stop();
    }
}

As you can see there is not much code. The Robo4J system gets the descriptor file,  can be initiated and started. When the code gets executed the system provides a simple API. Such API includes the default access path shown by the example below :


GET request command: $ curl localhost:9022
result[{"id":"ef514a70-3326-45a6-a1d2-469092563fc4","state":"STARTED"},{"id":"httpServer","state":"STARTED"}]



Conclusion: 
  The ability of single-file source code programs execution makes possible to prototype the IoT system (robots) just using a command line.  The reader may have noticed that the code is pretty straight forward. The important part is moved to the proper Robo4J XML Descriptor file definition. The Robo4J XML descriptor provides the links and configuration of all Robo4J Units that should be included. 
The following example can be also used for running more complex systems just by using available Robo4J Unit for the Lego or RaspberryPi platforms.
Enjoy Coding !





 

Sunday, December 2, 2018

Tracing the road,... on becoming a Java Champion


Few days ago I've been sitting in front of my laptop, I think was was coding some stuff, like a normal day :), and I accidentally opened my emails. The first email title I saw was : "Welcome to the Java Champions Program". 
I thought, what a nice Joke, because in the past I really wanted to become a Java Champion. But after reading this email more carefully, I found out that the email was real, no joke. After sorting this thing in my head I just run to my wife and son to share with them this amazing news. After all she is the one who tolerates my OpenJDK activities... due to her tolerance  I could achieve such goal. 

What is a Java Champion ? The answer can be found on the website [here] :
"The Java Champions are an exclusive group of passionate Java technology and community leaders who are community-nominated and selected under a project sponsored by Oracle. Java Champions get the opportunity to provide feedback, ideas, and direction that will help Oracle grow the Java Platform. This interchange may be in the form of technical discussions and/or community-building activities with Oracle's Java Development and Developer Program teams.

Members come from a broad cross-section of the Java community:

  • Java luminaries, senior developers, architects, and consultants
  • Academics
  • Authors of Java-related content (online & print) and industry conference speakers
  • Java User Group (JUG) leaders and the managers of Java-related portals"
After I left SUN Microsystem/Oracle I just continued to be involved very actively in Java community. When I thing about it closely, it is already almost 2 decades of my professional life spending on JVM technologies. I still work on JVM technologies on application design and architecture, currently at Volkswagen Group on some connect car related projects, more specifically at M.A.N. Truck & Bus.  

Outside of my duties, I'm quite proactive over many years. I'm doing reviews to technical books for the Pack Publishing, more specific for the following fields: Machine Learning, AI, JVM Technologies and Big Data. I've been also speaking over years at various conferences like JavaOne, CodeOne, Devoxx and others... It is always my pleasure to share the knowledge with the community to help moving things forward. I'm also blogging about various technologies and experiences [here].  
This year I've received the JavaOne/Code One Rock Star Award 2017. 
Two years ago I've started an OpenSource project. Working alone on the project was not so funny and I was happy that Marcus Hirt decided to join the team, and we work together. 

We called the project Robo4J. Robo4J [here] is the light weight framework for rapidly developing Robotics/IoT systems. We've received the Duke's Choice award 2017 for the work we have done on IoT Java field. 

Previously I've mentioned there was a time when I really wanted to become a JC, but ... Instead of being sad that I'm not a JC, I just continued to work on something else more intensively. I started to work with Marcus more closely and contributing to Java Mission Control / Flight Recorder project. The project has become a part part of OpenJDK [here] and I've become to be an Author
I'm really happy to see that the results of my contributions make a lot of people happy, more over I'm learning a lot from all OpenJDK contributors. This is the bright side, the dark side is that it costs a lot hours coding ;) And here I'm so thankful to my wife and son for understanding. 

I'm incredibly pleased to be accepted into the Java Champion program, I'm looking forward to represent ideals as good as I can. I'll give my best!



Saturday, December 1, 2018

Deep dive into distributed tracing with Spring Boot and Flight Recorder

Motivation
At Oracle CodeONE 2018 Marcus Hirt held very interesting presentation called "Diagnose Your Microservices: OpenTracing/Oracle Application Performance Monitoring Cloud [DEV5435]". This presentation gave an audience pretty intensive quick inside view to the large scale cloud application tracing.
Although his talk was not recorded, he has created pretty nice example, Robotshop, that he open-sourced.  You can find all information in his recently published blog posts (CLICK HERE). 
  His post also touched the Application Performance Management (APM) solutions that has been formed before OpenTracing standard has born.
  All intensive work crystallized into the previously mentioned OpenTracing standard, but what is it ?  As the web-site says It's a vendor-neutral APIs and instrumentation standard for distributed tracing (note: it's more about instrumentation). Companies like Datadog, Skywalking, Jaeger, LightStep are actively contributing into this standard, which is great news, it shows that the topic is pretty hot and we should probably think about it.
  Let's get back to my post topic. Many developers, world wide, are using spring-boot libraries stack to create a Spring based applications.

In this post you will learn how to connect some tracers (Jaeger, Zipkin) with your project. You will also learn how to connect Java Mission Control/Java Flight Recorder for very deep service analysis.

The post also stress the question how worthful it is to think about the application logging strategies. Why ? To be honest, who is reading couple of gigabytes big log files in order to spot the root case ;).  Who is writing continually very sophisticated regular expressions to get such information ?.

The source code is available on my GitHub account: [here] branch: [vehiclefactory-jfr-tracer]

Introduction
   In my previous post I've shown how to configure spring-boot project using opentracing [CLICK_HERE]. It was just  a simple producer consumer pattern based demo. In the following text we create a VehicleShop project with 4 independent micro-services : VehicleShopService, FactoryService, StorageService, CustomerService. All those services are spring-boot based ones.
The example project uses the Gradle build system. It does contain all services and you can start each of them separately, in docker or you can configure the docker-compose file.

  The monitoring is about to "extracting meaningful stories" from the defined Metrics (four golden signals, RED method etc.) or Logs (app events, stack-traces etc.), in other hand tracing is more about Spans, Spans analysis. Tracking gives the answer to individual request.
  What is such Span ? The Span is the primary building block of distributed trace. Such individual Span represents the work done within the distributed system. How we define such Span ?
By the opentracing standard Span has following properties:

  • an operation name
  • start and finish timestamp
  • key:value Span Tag
  • a SpanContext 
    • carries date across the process boundaries
Having defined Span we define the space from where such Span is coming from. Let's consider one individual Span,  we name it "Active Span". Such Span is responsible for the work accomplished by the surrounding code. Active Span has actually one very important property:
  • it can be only one Active Span inside the thread at time T.
Such property is managed by the Scope, which formalizes the activation and deactivation of a Span. 
OpenTracing standard defines the term Trace. Trace represents the interface which implementation creates the Spans.

The VehicleShop example 
Previously has been mentioned that VehicleShop project is the collection of micro-services. Those services are exchanging information between each other according to the schema (Img.1.)
Img.1.: VehicleShop project schema
The Customer service represents the set of the schedulers. Those schedulers generate a traffic that simulates the multiple customers behaviour like buying , searching or upgrading the car. The VehicleShop service sends requests to the vehicle elements storage (StorageService) in order to get information about available pieces. The VehicleShop sends requests to the FactoryService to check which cars are available to sell out.  The FactoryService before any car gets produces send the request to the StorageService whether the VehicleElement, necessary to build the car, are available (Img.2.)
Img.2.: example communication diagram
All services have enabled opentracing support by the following libraries:
opentracing-spring-jaeger-cloud-starter
opentracing-spring-zipkin-cloud-starter

when you add any of those libraries into the project class-path they will automatically configure the default tracer settings. You simple can start the tracer inside the docker container:
$docker run -d -p 6831:6831/udp -p 16686:16686 jaegertracing/all-in-one:latest
$docker run -d -p 9411:9411 openzipkin/zipkin:latest

Of course you can use the custom configuration of the tracer, but in such case you need properly re-configure spring @Configuration beans. The another alternative is to use the environment variables.
When the all services are up, you can open the Jaeger UI : http://localhost:16686/ (Img.3.)

Img.3.: JagerUI : VehicleShopService traces
The interface allows to analyze taken spans and observe a real application communication over the micro-services (Img.4.)

Img.4.: Tracing a specific request 
The Jaeger UI offers one very neat feature. It's ability to compare two spans by IDs. The span Id you can get from available traces (Img.5.)

Img.5.: Span comparison
As you can see the example architecture is very simple but it already shows the value of the tracing.

  Let's connect the example with Java Mission Control / Flight Recorder and see the traces from different perspectives.
  As the tracing provides you the ability to get the view into the application communication layer and here recognizing some potential issues, when the JFR is attached to the micro-service JVMs, you can directly analysize the potentially suspicious code.  It means that the trace may be very good initial signal to start the investigation.

Attaching Flight Recorder to the VehicleShop example
Marcus has recently published very neat library java-jfr-tracer . This library allows to record Scopes and Spans into the JDK Flight Recorder for very deep analysis.  To enable such feature it necessary to add following library into the project.

gradle.build:
implementation "se.hirt.jmc:jfr-tracer:0.0.3"

After having the library we need to register a new JFR Tracer, which is the wrap of the OpenTracing tracer, in following way:

@Autowired
public CustomTracerConfig(Tracer tracer) {
     GlobalTracer.register(new DelegatingJfrTracer(tracer));
}

Now information provided by tracers will be available also through the Flight Recorder interface through recorder Events (Img.6.)

Img.6.: Flight Recorder with recorded spans
The Flight Recorder gives you a chance to recognize a suspicious trace ids which may bring the significant value during the issue solving. The Spring framework is not just a one thread framework and using it may bring/open potential challenges (Img.7.)

Img.7.: VehicleShop threads view


Summary
Distributed Tracing is great and challenging.  As you can see from the image (Img.7.) there are bunch of threads and by adding new libraries to the project a new are coming. Distributed tracing is opening the way how to understand to what is really happening across the micro-services.
It means distributed tracing allows/supports:
  • distributed transaction monitoring
  • performance and latency optimization 
  • root cause analysis
  • service dependencies analysis
  • distributed context propagation
The only OpenTracing standard implementation may not be enough. Often you may need to know what is happening inside the specific one and the trace may forward you directly to the issue.

Using Flight Recorder for Distributed Tracing is like using "weapon" from different galaxy, it's not the silver bullet but it may be very close to it .

Enjoy the Demo and happy tracing!