Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Tuesday, December 1, 2015

Events events events...

Hi there,

As some of you might know I love the Internet of Things and so I have a couple of sensors around that measures different kind of data. I'm also a big fan of MQTT because it makes things so easy and with it's publish and subscribe model it seems to be a natural fit for a lot of IoT projects.

When playing with my own stuff on my server and on my home network I'm totally fine with using MQTT for all of my IoT related communications. 

BUT...if you ever spoke at conference venues like hotels you will find out that they are very strict with their network...means usually the ports you need for your MQTT communication are not open :(
Or if you work in a company with very strict rules you might have the same problem with the port availability.
For this years JavaOne I was playing around with an Application Container Cloud Service where I again had the same problem...only port 80/443 have been available for all communications.

So I remembered a conversation that I had with David Delabassee at JavaOne Brazil this year in June. He mentioned SSE (Server Sent Events) and that it might be a possible solution for these kind of problems. 

Hey hipsters...sure you can use WebSockets...BUT you might run into problems with Proxy Servers. And using WebSockets is not always needed. In my case I would like to visualize data that is coming from either a sensor or an IoT gateway. Usually I don't need to send data to these devices and even if I have to send data it will be rare.
So for such a use case SSE is a perfect fit because it is a unidirectional event stream from the server to the client.

My idea was to write some code that subscribes to MQTT topics on a given broker and forwards them to connected clients via SSE. Sounds easy...and it is easy :)

To be able to subscribe to specific topics I needed a simple REST endpoint in my code that accepts POST calls from the client. The POST endpoint takes the topic and the qos (Quality of Service) for the subscription as parameters.
The program will add the client with the subscribed topic to a map and everytime a new MQTT message arrives on the broker the message will be pushed to all subscribed SSE clients.

The following image hopefully explains what I had on my mind...

Image


As you can see on the image above you need at least a MQTT broker and a server that runs either Java SE or node.js or both :)

So I've implemented my little MQTT to SSE application in node and Java SE. Yes you read it right...Java SE...no Java EE :)
Don't get me wrong, Java EE is fine for a lot of things but if you just need something like I do here, it's just overkill and things like Spring Boot do better.

On Java EE it's also not that easy to make use of MQTT but on Java SE it's very easy if you use libraries like Eclipse Paho, FuseSource etc.

If you are not afraid of using JavaScript node.js is also a really good fit for stuff like this (even if I'm not the best JavaScript programmer I was able to write this app).

For those of you that can't wait...here are the links to the repositories.

MQTT to REST/SSE bridge and Java SE SSE client:


So in principle the whole app has only two methods one to publish a message via REST POST and one to subscribe to a topic via SSE.

In addition I've also created a HTML page and a Java SE client that both publish and subscribe messages to the MQTT broker using REST POST and SSE.


Set it up...

1. Setup a MQTT broker
If you don't have a broker yourself you might want to setup a free version over at www.cloudmqtt.com
After you signed up for the free Cute Cat plan you will find the settings of your MQTT broker in the Control Panel under details. There should be something like this...


Image

Just note the Server, User, Password and Port



2. Configure and Start the REST service

The node.js version:
If you use the node.js app you will find a file named config.js in the project. In this config.js file please add the url, user, password and port of your MQTT broker or the broker you host at cloudmqtt. This should look similar to the following picture...


Image

In principle you are now ready to start and if you've put the right credentials for your broker in the config.js file you should now be able to start the mqtt2sse.js file by calling

node mqtt2sse.js

on the command line or you start it from your preferred IDE.

The Java SE version:
If you use the Java SE based version you should find a config.properties file in the project directory. 
Just put the data like url, port, user and password of your MQTT broker or the broker you host at cloudmqtt in this file. It should look similar to the following one...

Image

Now you are ready to start the file eu.hansolo.mqtt2sse.Main either in your preferred IDE or you can also build the project and start the created fat jar from the command line as follows...

java -Dserver.port=8080 -jar mqtt2sse-1.0.jar

The application will make use of Spring Boot for the REST service and will simply output incoming messages on the command line.



3. Publish and Subscribe some messages via HTML/JavaScript
In both projects you will find a test.html file which simply displays incoming messages and will publish messages with random data every 5 seconds.

It will subscribe to the MQTT topic: 

sensor/+

which means it will receive every of the following messages...

sensor/NNN

The + is a MQTT wildcard and you can find more information about MQTT and topics over at the awesome guys from dc-square (creators of hivemq), here is a the link.

The HTML/JavaScript client will also publish messages every 5 seconds to the MQTT topic:

sensor/HtmlClient

The data it will publish looks like this...

{
  'temperature' : 23.24234,
  'pressure' : 1002.12312,
  'humidity' : 65.23414
}

So if you start it you should see something like the following in your browser...


Image



4. Publish and Subscribe some messages via Java
This Java app makes use of the jersey libraries to subscribe to SSE and HttpURLConnection to make the REST POST calls. The functionality is the same as with the HTML/JavaScript client, means it subscribes the MQTT topic

sensor/+

and publishes data to the MQTT topic

sensor/JavaClient

So every 5 seconds it will publish a messgae to the MQTT topic above. If you start the app you should see something similar on the console...


Image

As you can see it's in principle the same as with the HTML/JavaScript client.


5. Manually publish messages via REST POST
Finally you could also use a REST client like the Chrome App Postman (get it here) to manually publish a MQTT message via REST. 
On the following screenshot you can see how it looks like...


Image

So you have to add one header as follows...


Image

Select POST as the method to use and the following url: 

http://localhost:8080/publish

Now go to the Body tab and select raw. To publish something on the MQTT topic

sensor/Postman

put the following in the textarea...

{
  "topic"   : "sensor/Postman",
  "msg"     : "{\"temperature\":23.0,\"pressure\":1005.2,\"humidity\":60.0}",
  "qos"     : 0,
  "retained": false

}

If you now press the Send button you should see the new message in the HTML/JavaScript and the Java Client like on the following pictures...


Image

You could also use all clients at the same time and should see something like this...


Image

Because each client is subscribed to the MQTT topic sensor/+ it will show messages that arrive from itself and each other client.


6. Publish/Subscribe the messages in a MQTT client
Of course one could also use MQTT directly to publish/subscribe. Therefor I can recommend using MQTT.FX from Jens Deters. This tools is written in JavaFX and so it will run on all platforms. 

So if you publish messages from MQTT.FX it could look like this...


Image

And if the Java SE client is running the messages will appear like you can see here...


Image

And because the Java SE client is sending messages every 5 seconds you will also see the messages in MQTT.FX if you subscribe to the MQTT topic sensor/+


Image


So as you can see with this MQTT <-> SSE bridge kind of code you could use MQTT via REST and SSE. This might not be the ultimate solution but for my use case it's a perfect fit and if you like it...feel free to fork it...

Here are the links to the repositories:

MQTT to REST/SSE bridge and Java SE SSE client:



That's it for today...keep coding... 

Monday, June 17, 2013

Taming the Nashorn...AGAIN...

Hi there,
Like I said some post ago I will make use of the Nashorn scripting capabilities more often in the future and so here is another example.
To be honest I'm looking in the Nashorn scripting stuff only because I would like to improve my workflow for the Raspberry Pi embedded development. Usually I create and test the jar files on my desktop computer before I copy them via scp to the Raspberry Pi. On the Pi I then execute them on the command line. In principle this is ok but if you would like to test new things you have to do the modification-compile-copy procedure very often and that takes time. So the idea is that as soon as a new JDK8 developer preview for the Raspberry Pi is out (and hopefully contains Nashorn) I could create a Java application that loads a JavaScript file at runtime and executes the code in the JavaScript file. With this scenario I could edit the JavaScript file with nano for example and simply start the jar again. This would improve the development workflow a lot. So because we don't have Nashorn on the Raspberry Pi at the moment I have to test it on my desktop where it is part of the JDK8 developer preview already.

Example:
Let's take a gauge from the Enzo library that will look like this...

Image

The idea is to configure the gauge with default values if no JavaScript file is present and if there is a JavaScript file with a given name at the same place as the jar file it should be loaded and the configuration should be taken from the JavaScript file.
To realize that we first of all need a simple JavaFX application that contains the gauge.
So this is the code for that...

public class GaugeDemo extends Application {
    private Gauge gauge;

    @Override public void init() {
        gauge = new Gauge();
    }

    @Override public void start(Stage stage) {
        StackPane pane = new StackPane();
        pane.getChildren().add(gauge);

        Scene scene = new Scene(pane);

        stage.setTitle("Nashorn demo");
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

Simple...isn't it...? Ok, now let's create a method that configures the gauge with some default values. In this case we will define things like a title, a unit, some sections and modify the colors of the sections. So the code will look like this...

private void setGaugeDefaults() {
    gauge.setTitle("Default");
    gauge.setUnit("°F");
    gauge.setMinValue(32);
    gauge.setMaxValue(212);
    gauge.setSections(new Section(104, 140),
                      new Section(140, 176),
                      new Section(176, 212));
    gauge.setStyle("-needle       : rgb(  0,   0, 255);" +
                   "-section0-fill: rgb(  0, 255,   0);" +
                   "-section1-fill: rgb(255, 255,   0);" +
                   "-section2-fill: rgb(255,   0,   0);");

}

Please keep in mind that calling setStyle() is not the best way to set a JavaFX CSS style but it's ok for this example!!!

If we call this method in the init() method after we have initialized the Gauge object the result will look like this...

Image

So we now have the default style that should be used if no JavaScript file is present. So now we need a method to load a JavaScript file. We need the JavaScript file to be loaded into a String object that we could evaluate with the JavaScript engine. The code that we need to realize that looks like follows...

private String getScript(final String fileName) {
    StringBuilder scriptContent = new StringBuilder();
    try {
        Path         path  = Paths.get(fileName);
        List<String> lines = 
            Files.readAllLines(path, StandardCharsets.UTF_8);
        for(String line : lines) {
            scriptContent.append(line);
        }        
    } catch (IOException | URISyntaxException exception) {}
    return scriptContent.toString();

}

Now we are able to load a JavaScript file into a String so it's time to initialize the JavaScript engine...means unleash the Nashorn... :)
But before we can do that we need a JavaScript file. The idea is that we could pass the gauge object to the JavaScript file and modifiy the gauge within the JavaScript file.
So the JavaScript file will look like follows...

var ArrayList = java.util.ArrayList;
var Gauge     = Packages.eu.hansolo.enzo.gauge.Gauge;
var Section   = Packages.eu.hansolo.enzo.gauge.Section;

var obj = new Object();

obj.initGauge = function(gauge) {
    gauge.title      = 'Nashorn';
    gauge.unit       = '°C';
    gauge.minValue   = 0;
    gauge.maxValue   = 100;

    var sections     = new ArrayList();
    sections.add(new Section(40, 60));
    sections.add(new Section(60, 80));
    sections.add(new Section(80, 100));
    gauge.sections   = sections;

    gauge.style      = "-needle         : rgb(243,56,28);" +
                       "-section0-fill  : rgb(192, 215, 123);" +
                       "-section1-fill  : rgb(217, 191, 78);" +
                       "-section2-fill  : rgb(225, 75, 69);"

}

So the JavaScript above will initialize the gauge for measuring temperature in degree celsius where the setGaugeDefaults() method in our Java class will initialize the gauge for measuring the temperature in degree fahrenheit. Means it should be very easy to see if the script was loaded or not.
Because we could have more than one method in our JavaScript file that we might call in our Java code I created a method that loads the script once, get's the obj Object from the script an then we can use this script object to call the methods. So here is the method that will instantiate three member variables (the ScriptEngine, the so called Invocable and an Object that contains the JavaScript obj)...

private void initScript(final String script) {
    try {
        engine.eval(script);
        inv          = (Invocable) engine;
        scriptObject = engine.get("obj");
    } catch (ScriptException exception) { 
        script = ""
    }

}

Now we only have to add a method that will initialize the gauge object in dependence on the presence of a JavaScript file. So if the JavaScript file is present it should be taken to initialize the gauge otherwise the gauge should be initialized by calling the setGaugeDefaults() method. And here is the code...

private void initGauge() {
    gauge = new Gauge();
    if (script.isEmpty()) {
        // Default Gauge settings
        setGaugeDefaults();
    } else {
        // Settings from Script
        try {
            inv.invokeMethod(scriptObject, "initGauge", gauge );
        } catch (ScriptException | NoSuchMethodException | 
            RuntimeException exception) {
            // In case of an error set default values
            setGaugeDefaults();
        }
    }

}

With this method in place we are able to initialize our gauge by loading a JavaScript file during runtime...sweet.
So the complete Java code will look similar to this...

public class GaugeDemo extends Application {
    private static final String  SCRIPT_FILE_NAME = "config.js";
    private static final Charset ENCODING         = StandardCharsets.UTF_8;
    private ScriptEngineManager  manager;
    private ScriptEngine         engine;
    private String               script;
    private Invocable            inv;
    private Object               scriptObject;
    private Gauge                gauge;


    // ******************** Initialization ************************************
    @Override public void init() {
        manager = new ScriptEngineManager();
        engine  = manager.getEngineByName("nashorn");
        script  = getScript(SCRIPT_FILE_NAME);
        initScript(script);
        initGauge();
    }

    private void initScript(final String script) {
        try {
            engine.eval(script);
            inv          = (Invocable) engine;
            scriptObject = engine.get("obj");
        } catch (ScriptException exception) { 
            script = ""
        }
    }

    private void initGauge() {
        gauge = new Gauge();
        if (script.isEmpty()) {
            // Default Gauge settings
            setGaugeDefaults();
        } else {
            // Settings from Script
            try {
                inv.invokeMethod(scriptObject, "initGauge", gauge );
            } catch (ScriptException | NoSuchMethodException | 
                RuntimeException exception) {
                System.out.println("Error executing initGauge() in JavaScript");
                setGaugeDefaults();
            }
        }
    }


    // ******************** Methods *******************************************
    private void setGaugeDefaults() {
        gauge.setTitle("Default");
        gauge.setUnit("°F");
        gauge.setMinValue(32);
        gauge.setMaxValue(212);
        gauge.setSections(new Section(104, 140),
                          new Section(140, 176),
                          new Section(176, 212));
        gauge.setStyle("-needle         : rgb(0, 150,   0);" +
                       "-section0-fill  : rgb(0, 100, 150);" +
                       "-section1-fill  : rgb(0, 100, 200);" +
                       "-section2-fill  : rgb(0, 100, 255);");
    }

    private String getScript(final String fileName) {
        StringBuilder scriptContent = new StringBuilder();
        try {

            // ******** NEEDED FOR SCRIPT IN SAME FOLDER AS JAR ***************
            final URL    root       = GaugeDemo.class.getProtectionDomain()
                                               .getCodeSource().getLocation();
            final String scriptPath =
                (new File(root.toURI())).getParentFile().getPath() + 
                File.separator + fileName;
            // ****************************************************************            

            Path         path       = Paths.get(scriptPath);
            List<String> lines      = Files.readAllLines(path, ENCODING);
            for (String line : lines) {
                scriptContent.append(line);
            }
            System.out.println("Script: " + scriptPath + " loaded");
        } catch (IOException | URISyntaxException e) {}
        return scriptContent.toString();
    }


    // ******************** Start application *********************************
    @Override public void start(Stage stage) {        
        StackPane pane = new StackPane();
        pane.setPadding(new Insets(10, 10, 10, 10));
        pane.setPrefSize(400, 400);

        pane.getChildren().addAll(gauge);

        Scene scene = new Scene(pane);

        stage.setTitle("Nashorn JavaFX");
        stage.setScene(scene);
        stage.show();        
    }

    public static void main(String[] args) {
        launch(args);
    }

}

Be aware that in the code above the JavaScript file should be placed in the same folder as the jar. If you would like to load the JavaScript with an absolute path you simply could remove the block that is marked in the code and use the full path name for the SCRIPT_FILE_NAME constant.

If I start the code above the result looks like this...

Image

As you can see the gauge was initialized by loading and evaluating the JavaScript file "config.js".

So let's hope the Nashorn will find it's way to the JDK8 ARM developer preview very soon... :)

I hope you enjoy playing with the Nashorn as much as I do...so keep coding...

Tuesday, May 28, 2013

Taming the Nashorn (first impressions)...

Hi there,
JavaScript is everywhere these days and so it is also part of JDK8 dev. prev. with Project Nashorn which is a lightweight high-performance JavaScript runtime engine.
Because I never used Rhino (which is in principle the same just older and slower) I had no  idea how to use it and for what reason.
After I met Marcus Lagergren (@lagergren) at JAX in Mainz (Germany), Geecon in Krakow (Poland) and at Java Forum in Malmö (Sweden) I decided that I have to take a look at the Nashorn to get an idea on how to use it. Of course I'm especially interested on how to use Nashorn in combination with JavaFX. Lucky me that Nashorn is part of the weekly developer previews of JDK8 since a few weeks ago and because Jim Laskey (@wickund) blogged about this use case I was able to start with it yesterday.
After some starting problems I slowly begin to understand and would like to share it with you...
First of all I would like to see how I could use Nashorn with JavaScript in combination with my controls, so the idea is to visualize a Lcd control of my Enzo library with Nashorn.
For the following example you'll need the jdk8 developer preview (grab it here) and a current version of my Enzo library (grab it here).
And with a shell and a text editor you are good to go...really nice :)

So first of all we need to create a JavaScript file that should create a JavaFX application which should show the Lcd control and set's the value of the Lcd control every 3 seconds to a random value between 0 and 100.

This is the JavaFX code to realize that...

import eu.hansolo.enzo.lcd.Lcd;
import eu.hansolo.enzo.lcd.LcdBuilder;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

import java.util.Random;


public class EnzoFX extends Application {
  private Lcd            lcd;
  private Random         random;
  private long           lastTimerCall;
  private double         charge;
  private AnimationTimer timer;

  @Override public void init() {
    // Initialize the AnimationTimer
    random        = new Random();
    lastTimerCall = System.nanoTime();
    charge        = 0;
    timer         = new AnimationTimer() {
      @Override public void handle(long now) {
        if (now > lastTimerCall + 3_000_000_000l) {
          lcd.setValue(random.nextDouble() * 100);
          lcd.setTrend(Lcd.Trend.values()[random.nextInt(5)]);
          charge += 0.02;
          if (charge > 1.0) charge = 0.0;
          lcd.setBatteryCharge(charge);
          lastTimerCall = now;
          System.out.println(lcd.getValue());
        }
      }
    };

    // Initialize the Enzo Lcd control
    lcd = LcdBuilder.create()
                    .styleClass(Lcd.STYLE_CLASS_STANDARD_GREEN)
                    .title("Room Temp")
                    .unit("°C")
                    .decimals(2)
                    .minMeasuredValueDecimals(2)
                    .maxMeasuredValueDecimals(2)
                    .unitVisible(true)
                    .batteryVisible(true)
                    .alarmVisible(true)
                    .minMeasuredValueVisible(true)
                    .maxMeasuredValueVisible(true)
                    .lowerRightTextVisible(true)
                    .formerValueVisible(true)
                    .trendVisible(true)
                    .lowerRightText("Info")
                    .valueAnimationEnabled(true)
                    .foregroundShadowVisible(true)
                    .crystalOverlayVisible(true)
                    .build();
  }

  @Override public void start(Stage stage) {
    // Prepare stage and add controls
    StackPane root = new StackPane();
    root.setPadding(new Insets(10, 10, 10, 10));
    root.getChildren().add(lcd);

    stage.setTitle("Enzo in JavaFX");
    stage.setScene(new Scene(root, 528, 192));
    stage.show();

    // Start the timer
    timer.start();
  }

  public static void main(String[] args) {
    launch(args);
  }
}

Ok, so now we know how to achieve this in JavaFX but now let's take a look at the JavaScript code that leads to the same result. Here you go...

var System         = java.lang.System;
var Random         = java.util.Random;
var StackPane      = javafx.scene.layout.StackPane;
var Scene          = javafx.scene.Scene;
var Insets         = javafx.geometry.Insets;
var AnimationTimer = javafx.animation.AnimationTimer;
var Lcd            = Packages.eu.hansolo.enzo.lcd.Lcd;


// Initialize the AnimationTimer
var random        = new Random();
var lastTimerCall = System.nanoTime();
var charge        = 0;
var timer         = new AnimationTimer() {
    handle: function(now) {
        if (now > lastTimerCall + 3000000000) {
            lcd.value = random.nextDouble() * 100;
            lcd.trend = Lcd.Trend.values()[random.nextInt(5)];
            charge += 0.02;
            if (charge > 1.0) charge = 0.0;
            lcd.batteryCharge = charge;
            lastTimerCall = now;
            print(lcd.value);
        }
    }
}


// Initialize the Enzo Lcd control
var lcd   = new Lcd();
lcd.styleClass.add(Lcd.STYLE_CLASS_STANDARD_GREEN);
lcd.title                    = "Room Temp";
lcd.unit                     = "°C";
lcd.decimals                 = 2;
lcd.minMeasuredValueDecimals = 2;
lcd.maxMeasuredValueDecimals = 2;
lcd.unitVisible              = true;
lcd.batteryVisible           = true;
lcd.alarmVisible             = true;
lcd.minMeasuredValueVisible  = true;
lcd.maxMeasuredValueVisible  = true;
lcd.lowerRightTextVisible    = true;
lcd.formerValueVisible       = true;
lcd.trendVisible             = true;
lcd.lowerRightText           = "Info";
lcd.valueAnimationEnabled    = true;
lcd.foregroundShadowVisible  = true;
lcd.crystalOverlayVisible    = true;


// Prepare the stage and add controls
var root     = new StackPane();
root.padding = new Insets(10, 10, 10, 10);
root.children.add(lcd);

$STAGE.title = "Enzo with Nashorn";
$STAGE.scene = new Scene(root, 528, 192);
$STAGE.show();

// Start the timer
timer.start();

The JavaScript code that I saved to a file "javafx.js" looks not that different from the JavaFX code except...it's JavaScript...and the resulting application will look like this...

Image


You might ask yourself how you could run this code and here is the answer, all it takes is one call on the command line that looks like this:

/PATH/TO/JDK/jdk1.8.0.jdk/Contents/Home/jre/bin/jjs -cp /PATH/TO/LIBRARY/Enzo.jar -fx /PATH/TO/JS-FILE/javafx.js

Means you have to now the path to your jdk8 installation folder where you could find the jjs executable that is needed to start nashorn from the command line. In addition you have to add the Enzo.jar to the classpath so that you could use it within your JavaScript file and at last you have to call the JavaScript file with the -fx parameter which will start the application....BAM...that's all...sweet :)
I've put the commandline in a bash script so that I could call it by simple calling the bash script instead of typing the whole line over and over again.

If you start the javafx.js file you should see something like on this youtube video.

Ok you might say where is the advantage of using JavaScript to run a JavaFX application...just think about not starting an IDE, not compiling and building a JavaFX application just to make a short test. Isn't it be much nicer to simply have a small JavaScript, edit it with your default text editor and run it with from the command line with one single call...I really like that for testing things.

If you would like to know more about Nashorn you should definitely take a look at the Nashorn blog ,subscribe to the Nashorn mailing list and take a look at the Nashorn Wiki.

At this point I would say THANK YOU to Jim Laskey and Marcus Lagergren which helped me to getting this stuff done!!!

This is really a first test of using Nashorn with JavaFX but now that I know how to use it I will use more often...so stay tuned and keep coding...