Sunday, August 24, 2014

Update JavaFX BarChart in background thread, to display /proc/meminfo.

Similar to previous post "Display /proc/meminfo on JavaFX PieChart", this example show how to display memory usage, retrieved from /proc/meminfo, on JavaFX BarChart.



Another main point of this post is to show the different of loading data in various stage. There are three position in the code to load barchart data.
  • At position A: call prepareMemInfo() to load barchart data in JavaFX Application Thread, before UI show.
  • At position B, call prepareMemInfo() to load barchart data in JavaFX Application Thread, after UI show.
  • At position C, start another thread to load barchart data.
    In this case, another question rised: in prepareMemInfo(), the file /proc/meminfo is parsed in sequency, but add data to series2 in Application Thread by calling Platform.runLater(). May be it will not in the same sequency. <- I'm not sure here.
Check this video to know the different:


package javafx_meminfo;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleFloatProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

/**
 *
 * @web http://java-buddy.blogspot.com/
 */
public class JavaFX_meminfo extends Application {

    final static String FILE_MEMINFO = "/proc/meminfo";

    private final TableView<Record> tableMem = new TableView<>();
    ObservableList<Record> listRecords = FXCollections.observableArrayList();

    XYChart.Series series1 = new XYChart.Series();  //load in Application Thread
    XYChart.Series series2 = new XYChart.Series();  //load in Background Thread
    final CategoryAxis xAxis = new CategoryAxis();
    final NumberAxis yAxis = new NumberAxis();
    final BarChart<String, Number> barChart = new BarChart<>(xAxis, yAxis);

    @Override
    public void start(Stage primaryStage) {

        //position A - run in UI Thread, before UI show
        //prepareMemInfo();
        
        tableMem.setEditable(false);

        TableColumn colMemField = new TableColumn("Field");
        colMemField.setMinWidth(150);
        colMemField.setCellValueFactory(
            new PropertyValueFactory<>("memField"));

        TableColumn colMemValue = new TableColumn("Value");
        colMemValue.setMinWidth(100);
        colMemValue.setCellValueFactory(
            new PropertyValueFactory<>("memValue"));

        TableColumn colMemUnit = new TableColumn("Unit");
        colMemUnit.setMinWidth(50);
        colMemUnit.setCellValueFactory(
            new PropertyValueFactory<>("memUnit"));

        TableColumn colMemQty = new TableColumn("Qty");
        colMemQty.setMinWidth(200);
        colMemQty.setCellValueFactory(
            new PropertyValueFactory<>("memQty"));

        tableMem.setItems(listRecords);
        tableMem.getColumns().addAll(colMemField,
            colMemValue, colMemUnit, colMemQty);
        
        //Create a dummy ProgressBar running 
        ProgressTask progressTask = new ProgressTask();
        ProgressBar progressBar = new ProgressBar();
        progressBar.setProgress(0);
        progressBar.progressProperty().bind(progressTask.progressProperty());
        
        new Thread(progressTask).start();
        //---
        
        VBox vBox = new VBox();
        vBox.getChildren().addAll(tableMem, progressBar);

        StackPane root = new StackPane();
        root.getChildren().add(vBox);

        Scene scene = new Scene(root, 500, 250);

        primaryStage.setTitle("java-buddy");
        primaryStage.setScene(scene);
        primaryStage.show();

        //Open second window
        barChart.setTitle(FILE_MEMINFO);
        xAxis.setLabel("Field");
        yAxis.setLabel("Qty");
        barChart.getData().addAll(series1, series2);

        StackPane secondaryLayout = new StackPane();
        secondaryLayout.getChildren().add(barChart);

        Scene secondScene = new Scene(secondaryLayout, 500, 400);

        Stage secondStage = new Stage();
        secondStage.setTitle("Second Stage");
        secondStage.setScene(secondScene);

        //Set position of second window, related to primary window.
        secondStage.setX(primaryStage.getX() + 250);
        secondStage.setY(primaryStage.getY() + 20);
        secondStage.show();

        //position B - run in UI Thread, after UI show
        //prepareMemInfo();
        
        //position C - run in background Thread
        new Thread(BackgroundPrepareMemoInfo).start();
    }

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

    Runnable BackgroundPrepareMemoInfo = () -> {
        prepareMemInfo();
    };

    private void prepareMemInfo() {
        
        //dummy delay
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            Logger.getLogger(JavaFX_meminfo.class.getName()).log(Level.SEVERE, null, ex);
        }

        Stream<String> streamMemInfo = readFile(FILE_MEMINFO);
        streamMemInfo.forEach((line) -> {
            System.out.println(line);

            //split one line by whitespace/grouped whitespaces
            String[] oneLine = line.split("\\s+");

            for (String ele : oneLine) {
                System.out.println(ele);
            }

            System.out.println("---");

            String rField = "";
            int rMemValue = 0;
            String rMemUnit = "";

            if (oneLine.length <= 3) {
                if (oneLine.length == 3) {
                    rField = oneLine[0];
                    rMemValue = Integer.parseInt(oneLine[1]);
                    rMemUnit = oneLine[2];
                } else if (oneLine.length == 2) {
                    rField = oneLine[0];
                    rMemValue = Integer.parseInt(oneLine[1]);
                    rMemUnit = "B";
                } else if (oneLine.length == 1) {
                    rField = oneLine[0];
                    rMemValue = 0;
                    rMemUnit = "B";
                }

                Record record = new Record(
                    rField, rMemValue, rMemUnit);
                listRecords.add(record);

                if (Platform.isFxApplicationThread()) {
                    //It's running in UI Thread
                    series1.getData().add(new XYChart.Data(record.getMemField(), record.getMemQty()));
                } else {
                    //It's running in background Thread
                    Platform.runLater(() -> {
                        series2.getData().add(new XYChart.Data(record.getMemField(), record.getMemQty()));
                    });
                }

            }

        });
    }

    private Stream<String> readFile(String filePath) {
        Path path = Paths.get(filePath);

        Stream<String> fileLines = null;
        try {
            fileLines = Files.lines(path);
        } catch (IOException ex) {
            Logger.getLogger(JavaFX_meminfo.class.getName()).log(Level.SEVERE, null, ex);
        }

        return fileLines;
    }

    public static class Record {

        private final SimpleStringProperty memField;
        private final SimpleIntegerProperty memValue;
        private final SimpleStringProperty memUnit;
        private final SimpleFloatProperty memQty;

        private Record(String memField, int memValue, String memUnit) {
            this.memField = new SimpleStringProperty(memField);

            this.memValue = new SimpleIntegerProperty(memValue);
            this.memUnit = new SimpleStringProperty(memUnit);
            if (memValue == 0) {
                this.memQty = new SimpleFloatProperty(0.0f);
            } else if (memUnit.equalsIgnoreCase("MB")) {
                this.memQty = new SimpleFloatProperty((float) memValue * 1000000.0f);
            } else if (memUnit.equalsIgnoreCase("kB")) {
                this.memQty = new SimpleFloatProperty((float) memValue * 1000.0f);
            } else {
                this.memQty = new SimpleFloatProperty((float) memValue);
            }
        }

        public String getMemField() {
            return memField.get();
        }

        public int getMemValue() {
            return memValue.get();
        }

        public String getMemUnit() {
            return memUnit.get();
        }

        public float getMemQty() {
            return memQty.get();
        }

    }
    
    final int MAX_PROGRESS = 50;
    class ProgressTask extends Task<Void>{
         
        @Override
        protected Void call() throws Exception {
            for (int i = 1; i <= MAX_PROGRESS; i++) {
                updateProgress(i, MAX_PROGRESS);
                Thread.sleep(200);
            }
            return null;
        }
         
    }

}


Saturday, August 23, 2014

Beginning Java 8 Fundamentals: Language Syntax, Arrays, Data Types, Objects, and Regular Expressions

Beginning Java 8 Fundamentals: Language Syntax, Arrays, Data Types, Objects, and Regular Expressions

Beginning Java 8 Fundamentals provides a comprehensive approach to learning the Java programming language, especially the object-oriented fundamentals necessary at all levels of Java development.

Author Kishori Sharan provides over 90 diagrams and 240 complete programs to help beginners and intermediate level programmers learn the topics faster. Starting with basic programming concepts, the author walks you through writing your first Java program step-by-step. Armed with that practical experience, you'll be ready to learn the core of the Java language.

The book continues with a series of foundation topics, including using data types, working with operators, and writing statements in Java. These basics lead onto the heart of the Java language: object-oriented programming. By learning topics such as classes, objects, interfaces, and inheritance you'll have a good understanding of Java's object-oriented model.

The final collection of topics takes what you've learned and turns you into a real Java programmer. You'll see how to take the power of object-oriented programming and write programs that can handle errors and exceptions, process strings and dates, format data, and work with arrays to manipulate data.

What you’ll learn
  • How to write your first Java programs with an emphasis on learning object-oriented programming in Java
  • What are data types, operators, statements, classes and objects
  • How to do exception handling, assertions, strings and dates, and object formatting
  • What are regular expressions and how to use them
  • How to work with arrays, interfaces, enums, and inheritance
  • How to deploy Java applications on memory-constrained devices using compact profiles
Who this book is for
This book is for those who are new to Java programming, who may have some or even no prior programming experience.

Table of Contents
1. Programming Concepts
2. Writing Java Programs
3. Data Types
4. Operators
5. Statements
6. Classes and Objects
7. Object and Objects Classes
8. Wrapper Classes
9. Exception Handling
10. Assertions
11. Strings
12. Dates and Times
13. Formatting Data
14. Regular Expressions
15. Arrays
16. Inheritance
17. Interfaces
18. Enum Types
19. ASCII Character Set
20. Writing Documentation Comments
21. Compact Profiles

Display /proc/meminfo on JavaFX PieChart

Last post "Display /proc/meminfo on JavaFX TableView", it will be shown in PieChart form.


Please notice that this example aim to show data in chart form, not the actual presentation of memory allocation; for example, memFree should be a sub-set of memFree, not anoth section as shown on the piechart.

package javafx_meminfo;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
import javafx.application.Application;
import javafx.beans.property.SimpleFloatProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

/**
 *
 * @web http://java-buddy.blogspot.com/
 */
public class JavaFX_meminfo extends Application {

    final static String FILE_MEMINFO = "/proc/meminfo";

    private final TableView<Record> tableMem = new TableView<>();
    ObservableList<Record> listRecords = FXCollections.observableArrayList();
    
    ObservableList<PieChart.Data> pieChartData =
                FXCollections.observableArrayList();
    PieChart chart = new PieChart(pieChartData);

    @Override
    public void start(Stage primaryStage) {

        prepareMemInfo();
        tableMem.setEditable(false);

        TableColumn colMemField = new TableColumn("Field");
        colMemField.setMinWidth(150);
        colMemField.setCellValueFactory(
            new PropertyValueFactory<>("memField"));
        
        TableColumn colMemValue = new TableColumn("Value");
        colMemValue.setMinWidth(100);
        colMemValue.setCellValueFactory(
            new PropertyValueFactory<>("memValue"));
        
        TableColumn colMemUnit = new TableColumn("Unit");
        colMemUnit.setMinWidth(50);
        colMemUnit.setCellValueFactory(
            new PropertyValueFactory<>("memUnit"));
        
        TableColumn colMemQty = new TableColumn("Qty");
        colMemQty.setMinWidth(200);
        colMemQty.setCellValueFactory(
            new PropertyValueFactory<>("memQty"));
        
        tableMem.setItems(listRecords);
        tableMem.getColumns().addAll(colMemField, 
            colMemValue, colMemUnit, colMemQty);

        StackPane root = new StackPane();
        root.getChildren().add(tableMem);

        Scene scene = new Scene(root, 500, 250);

        primaryStage.setTitle("java-buddy");
        primaryStage.setScene(scene);
        primaryStage.show();
        
        //Open second window
        chart.setTitle(FILE_MEMINFO);
        
        StackPane secondaryLayout = new StackPane();
        secondaryLayout.getChildren().add(chart);
                 
        Scene secondScene = new Scene(secondaryLayout, 400, 300);
 
        Stage secondStage = new Stage();
        secondStage.setTitle("Second Stage");
        secondStage.setScene(secondScene);
                 
        //Set position of second window, related to primary window.
        secondStage.setX(primaryStage.getX() + 250);
        secondStage.setY(primaryStage.getY() + 100);
        secondStage.show();
    }

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

    private void prepareMemInfo() {

        Stream<String> streamMemInfo = readFile(FILE_MEMINFO);
        streamMemInfo.forEach((line) -> {
            System.out.println(line);

            //split one line by whitespace/grouped whitespaces
            String[] oneLine = line.split("\\s+");

            for (String ele : oneLine) {
                System.out.println(ele);
            }

            System.out.println("---");

            String rField = "";
            int rMemValue = 0;
            String rMemUnit = "";

            if (oneLine.length <= 3) {
                if (oneLine.length == 3) {
                    rField = oneLine[0];
                    rMemValue = Integer.parseInt(oneLine[1]);
                    rMemUnit = oneLine[2];
                } else if (oneLine.length == 2) {
                    rField = oneLine[0];
                    rMemValue = Integer.parseInt(oneLine[1]);
                    rMemUnit = "B";
                } else if (oneLine.length == 1) {
                    rField = oneLine[0];
                    rMemValue = 0;
                    rMemUnit = "B";
                }

                Record record = new Record(
                    rField, rMemValue, rMemUnit);
                listRecords.add(record);
                
                pieChartData.add(new PieChart.Data(
                    record.getMemField(), record.getMemQty()));
            }

        });
    }

    private Stream<String> readFile(String filePath) {
        Path path = Paths.get(FILE_MEMINFO);

        Stream<String> fileLines = null;
        try {
            fileLines = Files.lines(path);
        } catch (IOException ex) {
            Logger.getLogger(JavaFX_meminfo.class.getName()).log(Level.SEVERE, null, ex);
        }

        return fileLines;
    }

    public static class Record {

        private final SimpleStringProperty memField;
        private final SimpleIntegerProperty memValue;
        private final SimpleStringProperty memUnit;
        private final SimpleFloatProperty memQty;

        private Record(String memField, int memValue, String memUnit) {
            this.memField = new SimpleStringProperty(memField);
            
            this.memValue = new SimpleIntegerProperty(memValue);
            this.memUnit = new SimpleStringProperty(memUnit);
            if (memValue == 0) {
                this.memQty = new SimpleFloatProperty(0.0f);
            } else if (memUnit.equalsIgnoreCase("MB")) {
                this.memQty = new SimpleFloatProperty((float)memValue * 1000000.0f);
            } else if (memUnit.equalsIgnoreCase("kB")) {
                this.memQty = new SimpleFloatProperty((float)memValue * 1000.0f);
            }else {
                this.memQty = new SimpleFloatProperty((float)memValue);
            }
        }

        public String getMemField() {
            return memField.get();
        }

        public int getMemValue() {
            return memValue.get();
        }

        public String getMemUnit() {
            return memUnit.get();
        }

        public float getMemQty() {
            return memQty.get();
        }

    }

}