‚Äč claudinebroke.it

Claudine Broke It

Petit Workout - The Application

Posted on 19 April 2016

Hello again! Today we're going to continue working on the little workout application we instigated in my previous blog post. This post will cover the basic concepts behind generating a Graphical User Interface for a Java application :coffee:

JavaFX || Swing || AWT

Swing, JavaFX and AWT are GUI widget toolkits that offer components to allow the interaction between users and applications. Right away we can eliminate AWT from our potential application toolkit as it directly uses the operating system's components; meaning that the resulting application will not have the same look and feel on Ubuntu, Mac and Windows. This leaves us with Swing and JavaFX as candidates. Both are valid for our needs, however, Oracle corp. has determined that JavaFX is set to be replacing Swing as the GUI toolkit. This means that it isn't deprecated as of yet, but is receiving far less attention in the latest Java releases.

JavaFX Basics

Here is a simple visual representation of how a basic JavaFX application is structured:

 _____________________
| stage             x |
|  _________________  |
| | scene           | |
| |  _____________  | |
| | | layout pane | | |
| | |  _________  | | |
| | | | button  | | | |

So we need to add components (buttons, labels, graphics, etc.) to a layout, that is set within a scene, that is held within a stage.

In code, it looks like this:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class WorkoutQueueTest extends Application {

    private Label timerLabel;

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

    @Override
    public void start(Stage primaryStage) throws Exception
    {
        primaryStage.setTitle("Petit Workout");

        Button startBtn  = new Button("Start");
        startBtn.setOnAction((e) -> startWorkout());

        timerLabel = new Label("00:00:00");

        BorderPane pane  = new BorderPane();
        pane.setTop(startBtn);
        pane.setBottom(timerLabel);
        primaryStage.setScene(new Scene(pane, 300, 250));

        // @todo add terminate thread on close
        primaryStage.show();
    }

    public void startWorkout()
    {
        AnimationTimer animationTimer = new AnimationTimer() {
            long startTime = System.nanoTime();

            @Override
            public void handle(long now) {
                timerLabel.setText(
                    ReadableTimeConverter.convert(
                        toIntExact(
                            (now - startTime) / 1000000000
                        )
                    )
                );
            }
        };

        animationTimer.start();
    }
}

Labels and Buttons

Components classes offer more than one constructor, meaning that the argument count will determine what funtion is called. For example:

Label timerLabel = new Label();
timerLabel.setText("00:00:00");

Is the same as:

Label timerLabel = new Label("00:00:00");

This is because Java supports classes with multiple constructors, which means that the constructor being called is determined by its signature. This is called overloading constructers. If we dig a bit deeper, we can see that the Label class offers three different constructors:

/**
 * Creates an empty label
 */
public Label() {
    initialize();
}

/**
 * Creates Label with supplied text.
 * @param text null text is treated as the empty string
 */
public Label(String text) {
    super(text);
    initialize();
}

/**
 * Creates a Label with the supplied text and graphic.
 * @param text null text is treated as the empty string
 * @param graphic a null graphic is acceptable
 */
public Label(String text, Node graphic) {
    super(text, graphic);
    initialize();
}

This means that an often used actions such as adding text and graphics to a newly created Label and Button objects are accessible through a one-liner method call.

Buttons and Lambda Event Handling

Specific to buttons is the possibility to generate event listeners whose methods execute logic based on events and targets. In our case, we want to call upon the startWorkout method upon button click.

From the Java doc:

When a button is pressed and released a ActionEvent is sent. Your application can perform some action based on this event by implementing an EventHandler to process the ActionEvent.

And:

Lambda Expressions enable you to encapsulate a single unit of behavior and pass it to other code. You can use a lambda expressions if you want a certain action performed on each element of a collection, when a process is completed, or when a process encounters an error.

Starting Java 8, you can use anonynous (lambda) functions in your code:

startBtn.setOnAction((e) -> startWorkout());

This is a much more direct, easy-to-read and elegant way to execute the following:

startBtn.setOnAction(new EventHandler<ActionEvent>() {
    @Override
    public void handle(ActionEvent event) {
       startWorkout();
    }
});

So there's really no excuse in our case to not opt for the Lambda expression; the resulting smaller code footprint and straight-to-the-point syntax really improve legibility.

Layout Panes

Once we've created our buttons and labels, we need to place these on the application window. This is where the JavaFX SDK's layout container classes, such as BorderPane, StackPane, GridPane and FlowPane, come to our aid. You can manually lay out UI components by setting their position and size within your JavaFX application. However, using layouts makes it easier - and quicker - to manage the classic cases where you need such common layouts as rows, columns and tiles. It even covers repositioning elements upon window resize operations. Since Petit Workout, in its current iteration, is quite humble, we can use the basic BorderPane layout container, which looks like this:

 _______________________
| top                   |
|_______________________|
| left | center | right |
|______|________|_______|
| bottom                |
|_______________________|

Placing our elements is then as easy as using the set methods available with the BorderPane:

BorderPane pane = new BorderPane();
pane.setTop(startBtn);
pane.setBottom(timerLabel);

Scene and Stage -- Or putting it all together

primaryStage.setScene(new Scene(pane, 300, 250));
primaryStage.show();

Timer

Since we want to be as conservative as possible with thread usage in order to save resources, we can latch on to pre-existing runnable implementations to run a timer that monitors our workout. We can thus instantiate a new AnimationTimer that is associated to the JavaFX MasterTimer instance. In effect, this means that our AnimationTimer events will fire upon ever frame within our JavaFX application, much like the Swing redraw method.

long timestampOnInit = System.nanoTime();
AnimationTimer animationTimer = new AnimationTimer() {
    @Override
    public void handle(long now) {
        timerLabel.setText(
            ReadableTimeConverter.convert(
                toIntExact((now - timestampOnInit) / 1000000000)
            )
        );
    }
};

In effect, upon each frame execution, compare the current timestamp with the one we captured upon start button press. The resultant timestamp is afterward used to update our application's timer label with the elapsed time value converter as a ReadableTimeConverter value:

public class ReadableTimeConverter {

    /**
     * @param seconds
     * @return String
     */
    public static String convert(int seconds)
    {
        int hr  = seconds / 3600;
        int rem = seconds % 3600;
        int mn  = rem / 60;
        int sec = rem % 60;

        return (hr < 10 ? "0" : "") + hr + ":" + (mn < 10 ? "0" : "") + mn + ":" + (sec < 10 ? "0" : "") + sec;
    }
}

The advantage with this solution is that we are never dependent upon the CPU cycle's idea of a timestamp. If we were to instantiate a runnable instance set to execute, for example, every second, after some time we would start to see pretty severe discrepencies between our application's time and real time. This is because scheduled runnable tasks are dependent upon the CPU cycle's time. This can manifest in slower or faster times. So you could be, without knowing it, working out for a mear 40 minutes instead of a full 45; which is unacceptable ;)

Closing Statement

So this brings us a little closer to a fully working workout application. In the next blog post we'll integrate our producer-consumer thread pattern and add a countdown and intensity label to the GUI :excited:

As always, the code related to this blog post is available on my GitHub account.

Favorite Soup II

Posted on 14 April 2016

Leek, Turnip and Rice Soup

Time: 45 minutes

I've been battling a bit of a cold lately, and nothing makes me happier than warm, fagrant soup when I feel like this.

If you're a normal human being, then you used to hate turnip as a kid. When I saw the original recipe, I focused solely on the leeks and rice, and my brain completely made abstraction of the root vegetable required. This until I hit the grocery store aisle and ended up with the unsightly blob in my hand, and that is where I decided to give it a try. I did change my mind about brussel sprouts this year, so I decided to give turnips a try as an adult. I'm so glad I did! I owe my mom an apology, turnips aren't so bad.

Adapted from the New York Times

Ingredients

  • 1 tablespoon extra virgin olive oil
  • 3 large leeks, white and green parts, cleaned and sliced
  • 1 small turnip, sliced in 1/2 inch cubes
  • 2 garlic cloves, minced
  • 6 cups water
  • 1 vegetable bouillon cube
  • salt and pepper
  • 1 bay leaf
  • 1/2 cups of long brown rice
  • 2 handfuls of fresh italian parsley, chopped

Preparation

On medium, heat the oil in a large soup pot and add leek slices. Cook until the leeks begin to soften and add turnip. Stir often and cook for about 5 more minutes, or until leeks are fragrant and turnips are translucent. Add salt, pepper and garlic, cook for another minute. Add water, stock, bay leaf and rice. Set kitchen timer to 30 minutes, reduce heat to low, and go watch some netflix. Add fresh parsley to soup before serving.

Notes

I usually start by slicing the leek. Then, while the leek is softening in the pot, I cube the turnip. On the side, I also boil the required 6 cups of water in my electric kettle to speed up the soup making process.

Also, Leek and Turnip are best bought, in Quebec, in winter: calendar (fr)

Petit Workout Queue

Posted on 24 March 2016

Snow is clearing out, maple syrup is flowing, and the birds are coming back; spring is finally here! This means I'll soon be back on my bike exploring all the amazing land accessible on two wheels - yay! I can't even count how many how many boring hours I've spent on my stationary bike this winter trying to maintain my stamina, cardio and muscle. Now's the time to kick it up a notch, though, and maximize all these remaining living room workouts in order to be in the best shape possible when I hit the streets.

A great way to maximize workouts is to do interval training, i.e. executing series of exercises at difference intensity levels. I tried doing so using my phone's stopwatch, but sweat and phone don't match too well. Besides, how else was I going to learn Java? So I started building my own little workout application.

Petit Workout

The way our workouts (yes, now it is -our- workout) are to be structured is quite easy; each workout contains a series of intervals at specific intensity.

Workout example #1

+----+-----------+-----------+
|    |  Duration | Intensity |
+----+-----------+-----------+
|  0 |      6000 | "easy"    |
|  1 |      1000 | "hard"    |
|  2 |      3000 | "easy"    |
+----+-----------+-----------+

If we are to focus on the individual intervals, we get objects like the following:

public class Interval {

    private String intensity;
    private long duration;

    public Interval(String intensity, long duration) 
    {
        this.intensity = intensity;
        this.duration  = duration;
    }

    @Override
    public String toString() 
    {
        return "Interval{" +
            "intensity='" + intensity + '\'' +
            ", duration=" + duration +
            '}';
    }

    public String getIntensity() 
    {
        return intensity;
    }

    public long getDuration() 
    {
        return duration;
    }
}

As you can see, our Interval object is a quite basic data struture with getters to retrieve the intensity and duration of our Interval when needed. For our current iteration of the project, we're also implementing an @Override of the Object toString() method to cleanly format output during tests. Note that in Java, every class has the Object class as a superclass, all objects implement the methods of this class, including toString().

Now back to our series; one concept to extract from the table provided above is that we are effectively wanting to build a Collection of intervals. From the Java Api documentation:

A collection represents a group of objects, known as its elements.

That's pretty abstract, but also on point; a Collection is a group of objects. Defining an abstract concept allows us to narrow down on specific implementations that may better meet our application needs. In this case, Queues, which implement the Collection interface, seeem to fit the bill as they order elements in a FIFO (first-in-first-out) manner -- note that there are some exceptions to this ordering, like Priority queues, which we won't discuss as this is outside our project's scope.

In this little workout sequencing application, once an interval has terminated its execution, i.e. when its fulfilled its duration time, the application needs to initiate the next interval available in the queue.

Queue

There are many types of queuing patterns available through the Java API Collection interface. One of these concrete implementations is the LinkedList, which can be used to store and retrieve elements in a list

Note that Arrays, in Java, are reserved for primative types like integers, doubles, booleans, etc. and not objects, which include strings.

Here is an example of how we can use a LikedList as a Queue to generate our workout:

import java.util.LinkedList;

public class Queue {
    private LinkedList<Interval> intervalQueue = new LinkedList<>();

    public synchronized void put(Interval interval)
    {
        System.out.println("Queuing: " + interval);

        intervalQueue.addLast(interval);
        notifyAll();
    }

    public synchronized Interval take()
    {
        while (intervalQueue.size() == 0)
        {
            try
            {
                wait();
            }
            catch (InterruptedException e) {}
        }
        return intervalQueue.removeFirst();
    }
}

Three important concepts to extract from this class are that:

  1. Interacting with a LinkedList implementation that contains Interval objects (LinkedList<Interval>) effectively guarantees that we can call the getDuration and getIntensity methods on the queue's take return object.

  2. As we are going to implement multiple threads in our application, we need to assure no concurrency issues arise. Since the LinkedList implementation supplied by the Java Api is not synchronized, we may face conflicts if more than one thread attempts to access the list at the same time. The synchronized keyword tells the Java Virtual Machine to lock an object while it is being accessed by a thread, and to persist this lock until the first thread is finished with the object.

  3. A thread attempting to extract a value from the queue while the latter is empty will wait until an item is added. Also, when the thread attempting to remove an item from the buffer, it notifies other threads to let them know a new element is available for processing.

Now to interact with our queue! We need methods that put and take items to-and-from the list. There's actually a well know pattern for that: the Producer-Consumer pattern.

From Wikipedia:

The [Producer-Consumer] problem describes two processes [...] who share a common, fixed-size buffer used as a queue. The producer's job is to generate a piece of data, put it into the buffer and start again. At the same time, the consumer is consuming the data (i.e., removing it from the buffer) one piece at a time. The problem is to make sure that the producer won't try to add data into the buffer if it's full and that the consumer won't try to remove data from an empty buffer.

In other words, a Producer is a thread that produces new objects intended to be inserted into a queue, and a Consumer is the thread that processes the queued objects.

Producer

public class Producer implements Runnable {

    protected Queue queue;

    public Producer(Queue queue) {
        this.queue = queue;
    }

    public void run() {
        queue.put(new Interval("easy", 6000));
        queue.put(new Interval("hard", 1000));
        queue.put(new Interval("easy", 3000));
    }
}

Consumer

public class Consumer implements Runnable {

    protected Queue queue;

    public Consumer(Queue queue) {
        this.queue = queue;
    }

    public void run() {
        while (true) { consume(queue.take()); }
    }

    void consume(Interval x) {
        System.out.println("Pulling: " + x);
        try {
            Thread.sleep(x.getDuration());
        }
        catch (InterruptedException e) {}
    }
}

** note the dependency injection of the queue thread upon the Producer and Consumer objects. This is how the two classes communicate with each other.

Testing

public class QueueTest {

    public static void main(String[] args) throws Exception {

        Queue queue = new Queue();

        Producer producer = new Producer(queue);
        Consumer consumer = new Consumer(queue);

        new Thread(producer).start();
        new Thread(consumer).start();

    }
}

As you can see, this is a pretty rudamentary implementation. The Producer class places elements unto the queue, which the Consumer "takes" out of the queue. The Consumer does not take subsequent Interval objects until it has terminated a sleep() method with a duration

Queuing: Interval{intensity='easy', duration=6000}
Queuing: Interval{intensity='hard', duration=1000}
Queuing: Interval{intensity='easy', duration=3000}
Pulling: Interval{intensity='easy', duration=6000}
Pulling: Interval{intensity='hard', duration=1000}
Pulling: Interval{intensity='easy', duration=3000}

And that's that! Next up we will try to add a fun GUI :)