DataFX 8 Preview 2

A second preview build of DataFX has been released today. In a few hours the build can be found at maven central.

DataFX 8.0b2 contains the following modules:

  • datafx-core: General classes, concurrency support, controller API (MVC) & basic data readers
  • datafx-datareader: Implementations for the data reader API: REST, JSON, XML, JDBC, etc.
  • datafx-ui: Some special cell classes for table and list controls
  • datafx-websocket: Websocket support
  • datafx-featuretoggle: Support for feature toggles in JavaFX
  • datafx-ejb: Inject remote EJBs in your controller classes
  • datafx-flow: The Flow API to define complexe flows of several views

A short overview of all changes can be found in the DataFX group.

 

JavaFX CSS Utilities

Ever tried to add a Styleable property to a JavaFX Control or Skin? By doing so you can add additional CSS support to a Control type. Gerrit Grunwald has described the benefits of styleable properties in a blog post. One big problem is the boilerplate code that will be created when implementing these properties in a Control class. Here is an example how a Control with only one property will look like:

public class MyControl extends Control {
 
    private StyleableObjectProperty<Paint> backgroundFill;
 
    public Paint getBackgroundFill() {
        return backgroundFill == null ? Color.GRAY : backgroundFill.get();
    }
    public void setBackgroundFill(Paint backgroundFill) {
        this.backgroundFill.set(backgroundFill);
    }
    public StyleableObjectProperty<Paint> backgroundFillProperty() {
        if (backgroundFill == null) {
            backgroundFill = new SimpleStyleableObjectProperty<Paint>(StyleableProperties.BACKGROUND_FILL, MyControl.this, "backgroundFill", Color.GRAY);
        }
        return backgroundFill;
    }
 
    private static class StyleableProperties {
        private static final CssMetaData< MyControl, Paint> BACKGROUND_FILL =
                new CssMetaData< MyControl, Paint>("-fx-background-fill",
                        PaintConverter.getInstance(), Color.GRAY) {
                    @Override
                    public boolean isSettable(MyControl control) {
                        return control.backgroundFill == null || !control.backgroundFill.isBound();
                    }
                    @Override
                    public StyleableProperty<Paint> getStyleableProperty(MyControl control) {
                        return control.backgroundFillProperty();
                    }
                };
        private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
        static {
            final List<CssMetaData<? extends Styleable, ?>> styleables =
                    new ArrayList<CssMetaData<? extends Styleable, ?>>(Control.getClassCssMetaData());
            Collections.addAll(styleables,
                    BACKGROUND_FILL
            );
            STYLEABLES = Collections.unmodifiableList(styleables);
        }
    }
    @Override
    public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() {
        return getClassCssMetaData();
    }
    public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
        return StyleableProperties.STYLEABLES;
    }
     
}

That’s a lot of code for only one property. Therefore I created some helper classes to do all the work. These classes are part of the “css-helper” library that I released today.

Here is an example how the Control will look like when using the “css-helper” library:

public class MyControl extends Control {
 
    private StyleableObjectProperty<Paint> backgroundFill;
 
    public Paint getBackgroundFill() {
        return backgroundFill == null ? Color.GRAY : backgroundFill.get();
    }

    public void setBackgroundFill(Paint backgroundFill) {
        this.backgroundFill.set(backgroundFill);
    }

    public StyleableObjectProperty<Paint> backgroundFillProperty() {
        if (backgroundFill == null) {
            backgroundFill = CssHelper.createProperty(StyleableProperties.BACKGROUND_FILL, MyControl);
        }
        return backgroundFill;
    }
 
    private static class StyleableProperties {
        private static final CssHelper.PropertyBasedCssMetaData<TriangleButton, Paint> BACKGROUND_FILL = CssHelper.createMetaData("-fx-background-fill", PaintConverter.getInstance(), "backgroundFill", Color.LIGHTGREEN);
        private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES = CssHelper.createCssMetaDataList(Control.getClassCssMetaData(), BACKGROUND_FILL);
    }

    @Override
    public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() {
        return getClassCssMetaData();
    }

    public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
        return StyleableProperties.STYLEABLES;
    }
     
}

By using the static methods of the CssHelper class the code is much more readable.
But there is one problem with the API: It uses reflection internally and because of this the CSS algorithm will be slower as when using the first aproach. So the CssHelper should only be used for Controls that should not be part of an open source library and don’t appear often in the scene graph. If you need a special Control in your application or add a CSS property to an existing one you can use these classes to minimize the source code.

The Library is deployed to Maven Central and can be easily added to a Maven project:

<dependency>
    <groupId>com.guigarage</groupId>
    <artifactId>css-helper</artifactId>
    <version>0.1</version>
</dependency>

Reactive Programming with JavaFX

Java 8 is finally released and Lambda expression are an official part of Java. Thanks to this it’s much easier to write applications in a reactive way. One of the main concepts in reactive architecture is an event driven design. The reactive manifesto contains the following about event driven design:

In an event-driven application, the components interact with each other through the production and consumption of events—discrete pieces of information describing facts. These events are sent and received in an asynchronous and non-blocking fashion.

Reactive Programming with Java

By using Lambdas it’s very easy to define callbacks that can react on specific events. Here is a short example about an event driven design without the usage of Lambda expressions:

public static void hello(String... names) {
        Observable.from(names).subscribe(new Action1<String>() {

            @Override
            public void call(String s) {
                System.out.println("Hello " + s + "!");
            }

        });
    }

Thanks to Lambda expressions the same functionallity can be coded in Java 8 this way:

public static void hello(String... names) {
        Observable.from(names).subscribe((s) -> System.out.println("Hello " + s + "!"));
    }

The example is part of the RxJava tutorial.

Reactive Programming with JavaFX

Let’s take a look at JavaFX. Because the JavaFX API was designed for Java 8 it provides a lot of Lambda support and callbacks are used a lot. But next to the default JavaFX APIs there are currently an open source projects that adds a lot of reactive design and architecture to the JavaFX basics: ReactFX.
By using ReactFX you can do a lot of cool event driven stuff with only a few lines of code. Here is an example how event handlers can be designed to react on user inputs:

EventStream<MouseEvent> clicks = EventStreams.eventsOf(node, MouseEvent.MOUSE_CLICKED);
clicks.subscribe(click -> System.out.println("Click!"));

I think the API provides a lot of cool functionallity that let you design JavaFX applications that are more reactive and I hope to see a lot of more code like shown in the example above.

Summery

The are currently 2 cool reactive APIs for Java out there: RxJava for a basic use in Java and ReactFX that is specialized for JavaFX. Theoretically you can do everything (or most of the stuff) you can do with ReactFXwith the help of RxJava, too. But here you need to concern about the JavaFX Application Thread. Because ReactFX is implementated for JavaFX (or a single threaded environment) you don’t need to handle this. A first comparison of this two libraries can be found here.

Mastering JavaFX Controls

In summer my first JavaFX book will be released and I created a first info page about the book. I will add additional informations the next days and hopefully there will be a free downloadable chapter in the next weeks. I plan to add all sources and demo applications that are mentioned in the book to the page.
You can find all information here: Mastering JavaFX Controls

JavaFX meets JavaEE

At JavaOne Arun Gupta gave me a copy of his “Java EE 7 Essentials” book. I don’t want to write a complete review of the book, but if you are interested in the Java EE platform this book is perfect. It covers all the different specifications that are new or polished in Java EE 7 in several chapters and gives a very good overview to all the technologies and how to use them.

book

After reading the book you are ready to develop a web application that is based on JEE 7. Most of this applications will have a web frontend that is based on JSF as it is shown in the book, too. But as I mentioned in a earlier post, a modern business applications often needs support for mobile or desktop applications:

3tier

 

Java EE supports different middelware standards for this purpose. In this article I will show you the different Java EE specifications and how you can combine them with JavaFX. If you have seen oracles technical keynote at JavaOne this year you will know what I’m talking about. I think that  multi client support by using a standardize middelware was one of the key conclusions of the keynote.

To do so I will mainly use DataFX APIs at client site because DataFX is made for exactly the described goal: Connect your desktop application with a server and use all the best practice methods that are originated by enterprise development in your desktop app. In Aruns book you find all JavaEE specifications separated by chapters. I will do the same and handle the following technologies:

  • RESTful Web Services
  • JSON Processing
  • WebSocket
  • SOAP-Based Web Services
  • JavaServer Faces
  • Contexts and Dependency Injection
  • Concurrency Utilities
  • Bean Validation
  • Java Persistence
  • Java Message Service
  • Enterprise JavaBeans
  • Servlets

Aruns book covers the topics “Java Transaction” and “Batch Processing”, too. This two topics are extremely JEE related and currently don’t fit in the topic of this article.

RESTful Web Services

As described in Aruns book JavaEE has a specification for REST based webservices. This specification isn’t new in Java EE 7 and is surely used in a lot of applications. To create a simple communication between a client and a server REST is of course a good choice. By using REST the client can call URLs to get, create or delete data on server site, for example. The access to REST endpoints was one of the first DataFX features. By using the API you can simple access REST endpoints. Because a lot of applications support REST (Twitter, Facebook, Google Maps, …) you can easily retrieve data from this applications. With DataFX 2.0 we added write support. Now you can get data from a server and post new or edited data back by simply using REST. If you use DataFX for this approach you even don’t need to handle multithreading issues. DataFX will handle all this stuff for you. You will find more informations about REST based access in our JavaOne slides or in this tutorial.

JSON Processing

With version 7 JSON support is added to JavaEE. By using JSON you can convert your data object to a human and machine readable format. I think, that JSON is the best format to provide data to a client. With JEE 7 can convert your data object to a JSON string and vice versa. Because this is a new part of JavaEE 7 it is treated in Arun Guptas book with an own chapter. After reading you are ready to create endpoints that send and receive JSON based data. By using DataFX it is really simply to handle the JSON data. The API provides a JSONConverter that can create Java objects from JSON strings. This can be easily done by using Jackson annotations. DataFX will convert the JSON data automatically.

WebSocket

DataFX provides special DataSources that can be used to connect to a WebSocket server endpoint and send or receive custom data. DataFX uses the default websocket specification here that is part of JEE 7.

SOAP-Based Web Services

SOAP webservice are already part of Java EE since version X. Because most modern application use REST or websocket in combination with JSON there is currently no SOAP support in DataFX. But we discussed this topic and hope to provide a SOAP API in a later version of DataFX. Because JavaSE already supports SOAP you can easily create your own client API until DataFX will support it. You can find a example here.

JavaServer Faces

For most web applications the user interface is defined as a HTML based view. With JEE you can use JSF to define this views and bind your business date to a page. If you develop a JavaFX client you will normally use FXML to define your views. With Java EE 7 JSF is extended by the flow API. With this API you can define flows in your application. A flow is a linkage of some pages. A good example for a flow is the checkout process in a webshop. You have some pages that are bind by some navigation rules and share data like the credit card informations. Here is an example how a (master-detail) flow can look:

m-d

With DataFX 2.0 we will introduce the flow API. By using this API you can simply define FXML based flows. Each view is defined by a controller class that has a binding to the FXML based view. You can simply connect views and add actions to the views. The flow API uses the DataFX controller API that was shown in our JavaOne session. But because the API is still in development it has already changed in some parts. You can check out the latest version in our DataFX source repository.

Contexts and Dependency Injection

As shown in one of my last posts DataFX supports context dependency injection in controllers. Currently Providers, etc. are not supported. This will be one of the next features that we want to add. DataFX currently support the following scopes:

  • viewScope
  • flowScope
  • applicationScope

Concurrency Utilities

With JEE 7 you can use Executor instances in your business app. In DataFX we provide different classes and utility functions to provide a great support for concurrency. Next to invokeLater(…) method that is part of JavaFX you can find invokeAndWait(…) utility methods in DataFX-core. These can be used to create your own background task API. In addition DataFX provides a new Executor class that supports JavaFX properties. In most cases you can use the DataReader API of DataFX to handle background tasks. In some special cases you can use the ProcessChain class that will be new in DataFX 8.

Bean Validation

Thanks to JEE we have a default specification for bean validation. DataFX uses this specification, too. By doing so a developer doesn’t need to learn new APIs. All the annotations and interfaces that are part of JSR 303 can be used in DataFX. A first example how bean validation works in DataFX can be found here.

Java Persistence

JPA is the specification for accessing relational databases in JEE. The API can simply be used in JavaFX, too. With the help of DataReaders and the ProcessChain JPA queries can simply be called as background tasks. Today a developer need to implement custom data sources here. We plan to add a better support with DataFX 8 :)

Java Message Service

Ok, what should I say: This issue is completely open in DataFX. Currently there is no support for JMS.

Enterprise JavaBeans

EJBs are still a very important part of JEE applications. A EJB can be defined as a local or remote bean. A local bean can only be accessed from the same enterprise application and a remote EJB can theoretically accessed from everywhere. The JEE application containers provide different functions how a remote application can access these EJB. The support for EJBs will come with DataFX 8. A first version is finished and nosy developers can find the sources and examples in the DataFX sources at Bitbucket. I plan to blog about EJB support in the next days ;)

Servlets

A Servlet is a very general class in JEE and for example REST services can be implemented by using Servlets. REST his supported by DataFX. Servlets provide some additional functionality. Currently there is no deeper support in DataFX.

Summery

Hope you like this overview of DataFX. If you want to know more about these technologies on server side buy Arun Gupta’s “Java EE 7 Essentials” book. For the client part you should take a look at DataFX. If you have any comments, additional ideas or critic about the features of DataFX please add a post to our Google Group.

DataFX 8 Preview 2: The ProcessChain

Some time ago I gave a first preview of the new APIs and functions in DataFX 8. We are currently plan to release DataFX 8 once JavaFX 8 is released. I plan to blog about the new features in DataFX in the next weeks. By doing so we hope to receive some useful feedback. In the last preview I described the controller and flow API of DataFX. Today I will show you only only small class :)

Next to new APIs we added some helpful classes to the DataFX core packages. The class that I want to show you today is one of these new classes: The ProcessChain.

The ProcessChain can be used to create a task chain. A task can be run on the “JavaFX Application Thread” or on a background thread. Some of you may know the SwingWorker class that was a important tool when working with background tasks in Swing. With the ProcessChain you can do similar stuff but thanks to Java 8, Lambdas and functional interfaces this class is more powerful that SwingWorker ever was.

Let’s think about a dialog that loads some data from a server. This can be done by clicking a button. Whenever the button is pressed the following workflow should be executed:

  • Disable Button
  • Communicate with Server
  • Enable Button

The button must enabled and disabled on the “JavaFX Application Thread” but you should not communicate with the server on this thread cause it will freeze the application. Because of that the communication must be executed on a extra thread:

  • Disable Button (Application Thread)
  • Communicate with Server (Background-Thread)
  • Enable Button (Application Thread)

The ProcessChain is a fluent API that can be used to create this workflows in JavaFX. Because its a chain you can add as many task as you want. The ProcessChain can use Lambdas and pass task results to the next Task. The following default interfaces can be used here:

  • java.util.function.Function
  • java.util.function.Supplier
  • java.util.function.Consumer
  • java.lang.Runnable

Here is a simple example:

Label label = new Label("No data");
Button button = new Button("Press me“);

button.setOnAction(new EventHandler() {

    public void handle(ActionEvent event) {

        new ProcessChain().inPlatformThread(() -> button.setDisable(true))
            .inExecutor(() -> communicateWithServer())
            .inExecutor(() -> {return "Time in Millis: " + System.currentTimeMillis();})
            .inPlatformThread((Consumer) (t) -> label.setText(t.toString()))
            .inPlatformThread(() -> button.setDisable(false))
            .run();
    }
});

As you can see in the example it is very easy to create a chain with the API. By using the inExecutor(…) or inPlatformThread(…) method a developer can choose if a task should run on the “JavaFX Application Thread” or in background.

In addition tasks can publish its result and use the result of the previous one. Here the new Java 8 interfaces Function, Supplier and Consumer can be used to define tasks with an input or output value.

The DataReader API is still part of DataFX of course. If you use DataReaders you shouldn’t need the shown API or can add all tasks to the Platform thread. But sometimes there are issues where you need to create your own custom background tasks. In these cases the ProcessChain is your friend ;)

DataFX Controller Framework Preview

Today we released the version 2.0 of DataFX. Thanks for all the feedback that we received with the last release candidates. As a next step we will work on DataFX 8.0 that will use Java 8 and JavaFX 8. One of the new features that will be part of the next release are currently in development. Today I will show a first preview to DataFX 8.0.

The last month I added a new framework to DataFX. This framework should help to create the views of applications, define actions on them and create flows that contain a subset of views.

To show the features of the framework I will create a simple JavaFX application. The app should manage persons. Persons can be loaded, created, edited and deleted by the app. Let’s have a first look on the general concept of the application:

datafx1

As you can see the app contains 3 different views:

  • a master view that shows all persons in a list
  • a create view that can add a new person
  • a edit view to edit a person

All this views are linked by actions (“save”, “add”, etc.) that will manipulate the data or show another view. First of all we want to take a look on the data model. Here a simple Person class is defined:

public class Person {

    private StringProperty name;

    private StringProperty notes;

    public Person() {
    }
     
    public Person (String name, String notes) {
        setName(name);
        setNotes(notes);
    }
     
    public String getName() {
        return nameProperty().get();
    }

    public StringProperty nameProperty() {
        if(name == null) {
            name = new SimpleStringProperty();
        }
        return name;
    }

    public final void setName(String name) {
        this.nameProperty().set(name);
    }

    public String getNotes() {
        return notesProperty().get();
    }

    public StringProperty notesProperty() {
        if(notes == null) {
            notes = new SimpleStringProperty();
        }
        return notes;
    }

    public final void setNotes(String notes) {
        this.notesProperty().set(notes);
    }

    @Override
    public String toString() {
        return getName();
    }
}

This class defines a person. Because we want to handle a list of persons we need another class that in our case defines the global data model:

public class DataModel {

    private ListProperty<Person> persons;

    private IntegerProperty selectedPersonIndex;

    public ListProperty<Person> getPersons() {
        if (persons == null) {
            ObservableList<Person> innerList = FXCollections.observableArrayList();
            persons = new SimpleListProperty<>(innerList);
        }
        return persons;
    }

    public int getSelectedPersonIndex() {
        return selectedPersonIndexProperty().get();
    }

    public void setSelectedPersonIndex(int selectedPersonIndex) {
        this.selectedPersonIndex.set(selectedPersonIndex);
    }

    public IntegerProperty selectedPersonIndexProperty() {
        if (selectedPersonIndex == null) {
            selectedPersonIndex = new SimpleIntegerProperty();
        }
        return selectedPersonIndex;
    }
}

This class defines a list of persons and the currently selected person by an index. To create a first default set of persons that can be loaded we define a additional class. In a real world application this class could wrap a database connection, for example:

public class LoadPersonsTask implements Runnable {
    
    Person[] persons = {
        new Person("Johan Vos", "Johan is CTO at LodgON, a Java Champion, a member of the BeJUG steering group, the Devoxx steering group and he is a JCP member."),
        new Person("Jonathan Giles", "Jonathan Giles is the JavaFX UI controls technical lead at Oracle, where he has been involved with JavaFX since 2009."),
        new Person("Hendrik Ebbers", "Hendrik Ebbers is Senior Java Architect at Materna GmbH in Dortmund, Germany.")};
    
    @Inject
    private DataModel model;
    
    @Override
    public void run() {
        model.getPersons().clear();
        ListDataProvider<Person> ldp = ListDataProviderBuilder.<Person>create()
                .dataReader(new ArrayDataReader(persons))
                .resultList(model.getPersons())
                .build();
        ldp.retrieve();
    }
}

After the data model is defined we can create the first view. Let’s start with the master view. To create the view Scene Builder can be used. Here we can easily design the following view:
datafx2
For all needed controls IDs are defined in the FXML. Normally you need to define a controller class in FXML. This is not needed for the DataFX Controller API. Instead of this we can bind a controller and a FXML view by the use of an annotation. As the next step a controller is needed. As a first step we create a small controller with some additional annotations:

@FXMLController("listView.fxml")
public class MasterViewController {

@FXML
private Button editButton;

@FXML
private Button removeButton;

@FXML
private Button addButton;

@FXML
private Button loadButton;

@FXML
private ListView dataList;
}

In this first version there is only one difference to the default JavaFX APIs: The FXMLController annotation is added. This annotation defines the link between the controller class and the FXML file. As a next step we want to create a data model. Here the next benefit of the framework can be used: Context Dependency Injection. To add a model to the the controller we can simple inject it:

@Inject
private DataModel model;

To explain what happens here the CDI module in DataFX need to be described a little bit more. As in JEE CDI different scopes are supported in DataFX:

  • ViewScope
  • FlowScope
  • ApplicationScope

All this scopes have a different context is is managed by the framework. All items that are part of the ViewScope have a lifetime of one view. A view is for example the master view in our example. The Application scope is defined as a global scope. All items in this scopes are singletons. The Singleton scope that is already defined in javax.inject can be used here, too. The flow scope defines a flow of views. In our example we will create one flow that handles all the defines views. In a more complex applications different flows can be handled. You can easily create a flow for each tap in a business application, for example. Additionally DataFX supports the dependent scope as it is defined in JEE.

The data model in our application need to be defined in the flow scope. It should be accessed from all views in this scope. To do so a scope annotation need to be added to the class:

@FlowScoped
public class DataModel {
...
}

Once this is done we can easily inject the data model in our view:

@FXMLController("listView.fxml")
public class MasterViewController {
     
    ...
 
    @Inject
    private DataModel model;
 
}

As a next step some initial setup is needed. To do so the PostConstruct annotation is supported by the DataFX framework:

@FXMLController("listView.fxml")
public class MasterViewController {
 
    ....
 
    @PostConstruct
    public void init() {
        dataList.itemsProperty().bind(model.getPersons());
        model.selectedPersonIndexProperty().bind(dataList.getSelectionModel().selectedIndexProperty());
    }
}

Now the ListView is bounded to the data model. To create some basic data a action is needed. This action should fire when the “load” button is pressed. First we create a simple class that handles the action:

public class LoadPersonsTask implements Runnable {
     
    Person[] persons = {
        new Person("Johan Vos", "Johan is CTO at LodgON, a Java Champion, a member of the BeJUG steering group, the Devoxx steering group and he is a JCP member."),
        new Person("Jonathan Giles", "Jonathan Giles is the JavaFX UI controls technical lead at Oracle, where he has been involved with JavaFX since 2009."),
        new Person("Hendrik Ebbers", "Hendrik Ebbers is Senior Java Architect at Materna GmbH in Dortmund, Germany.")};
     
    @Inject
    private DataModel model;
     
    @Override
    public void run() {
        model.getPersons().clear();
        ListDataProvider<Person> ldp = ListDataProviderBuilder.<Person>create()
                .dataReader(new ArrayDataReader(persons))
                .resultList(model.getPersons())
                .build();
        ldp.retrieve();
    }
}

As you can see the injected model is used here, too. This task can be added to the button by the use of the Flow API. This API defines a flow through all views. The first very simply version of our flow looks like this:

Flow flow = new Flow(MasterViewController.class).
                withTaskAction(MasterViewController.class, "load", LoadPersonsTask.class);

This defines a flow that starts with the master view and adds a task action to this view. The action is defined by the id “load”. To bind this action to the load button only a additional annotation is needed in the controller:

@FXML
@FXMLFlowAction("load")
private Button loadButton;

Now the first version of the application can be started. To do so we need a main class that adds the flow to a JavaFX scene:

public class DataFXDemo extends Application {
    public static void main(String[] args) {
        launch(args);
    }
    @Override
    public void start(Stage stage) throws Exception {
        Flow flow = new Flow(MasterViewController.class).
                withTaskAction(MasterViewController.class, "load", LoadPersonsTask.class);
 
        DefaultFlowContainer container = new DefaultFlowContainer();
        flow.createHandler().start(container);
 
        Scene scene = new Scene(container.getPane());
        stage.setScene(scene);
        stage.show();
    }
}

The DefaultFlowContainer class is used in the code. This class is a default implementation of a Pane that wraps a flow. When you start the application the “load” button can be used to load the list of persons. Because of the JavaFX binding the result will be shown directly:
datafx3
As a next step we want to add the edit action to the application. Here an additional view need to be created by Scene Builder:
datafx4
Additionally a controller class is needed. This class uses the described features:

@FXMLController("detailView.fxml")
public class EditViewController {
 
    @FXML
    @FXMLFlowAction("save")
    private Button saveButton;
 
    @FXML
    private TextField nameField;
 
    @FXML
    private TextArea notesTextArea;
 
    @Inject
    private DataModel model;
 
    @PostConstruct
    public void init() {
        Person p = model.getPersons().get(model.getSelectedPersonIndex());
        nameField.textProperty().bindBidirectional(p.nameProperty());
        notesTextArea.textProperty().bindBidirectional(p.notesProperty());
    }
}

The data model is injected to the controller. Because it is defined in the flow scope it will be the same instance as in the master view. Additionally some bindings will be created to bind the UI controls to the data model. A flow action is added to the save button. This action is defined by the “save” ID. To add this view to the flow only some additional code is needed:

Flow flow = new Flow(MasterViewController.class).
               withLink(MasterViewController.class, "edit", EditViewController.class).
               withLink(EditViewController.class, "save", MasterViewController.class).
               withTaskAction(MasterViewController.class, "load", LoadPersonsTask.class);

As you can see two links are added to the flow. This links are actions that will change the current view of the flow. In this cases we want to link from the master page to the edit page and vice versa. When you start the application now you can edit all persons that are part of the list:
datafx5
As a next step we want to add the remove action to the master view. This can be easily done by adding another action:

public class RemoveActionTask implements Runnable {
    @Inject
    private DataModel model;
    @Override
    public void run() {
        model.getPersons().remove(model.getSelectedPersonIndex());
    }
}

As the import action this action need to be defined in the flow and bound to a button:

@FXML
@FXMLFlowAction("remove")
private Button removeButton;

Additionally the flow need to be changed:

Flow flow = new Flow(MasterViewController.class).
               withLink(MasterViewController.class, "edit", EditViewController.class).
               withLink(EditViewController.class, "save", MasterViewController.class).
               withTaskAction(MasterViewController.class, "remove", RemoveActionTask.class).
               withTaskAction(MasterViewController.class, "load", LoadPersonsTask.class);

The Flow API of DataFX supports different types of actions. The link action and the task action are used in this example until now. As a next step we want to add the view to create new persons. Here we will use some additional features of the framework.
Because the view should look like the edit view we can reuse the FXML here. Additonally a controller is needed. Here is a first basic version:

@FXMLController("detailView.fxml")
public class AddViewController {
 
 
    @FXML
    @FXMLFlowAction("save")
    private Button saveButton;
 
 
    @FXML
    private TextField nameField;
 
 
    @FXML
    private TextArea notesTextArea;
 
 
    private StringProperty nameProperty = new SimpleStringProperty();
 
 
    private StringProperty noteProperty = new SimpleStringProperty();
 
    @Inject
    private DataModel model;
 
    @PostConstruct
    public void init() {
        nameField.textProperty().bindBidirectional(nameProperty);
        notesTextArea.textProperty().bindBidirectional(noteProperty);
    }
}

The data that is added in the view will be stored in the two properties that are defined in the view. Once everything is fine a new person should be created and added to the data model. To do so we use a new action type: The MethodAction. With this type a method of the controller can easily bound to an button. To do so we add a method with the needed annotation in the controller class:

@FXMLController("detailView.fxml")
public class AddViewController {
 
@FXML
@FXMLFlowAction("save")
private Button saveButton;
 
...
 
@ActionMethod("addPerson")
    public void addPerson() {
        Person p = new Person();
        p.setName(nameProperty.get());
        model.getPersons().add(p);
   }
 
}

Like all other actions this action need to be added to the flow. Because we want to add the person to the data model and then jump back to the master view a action chain is used here:

Flow flow = new Flow(MasterViewController.class).
               withLink(MasterViewController.class, "edit", EditViewController.class).
               withLink(MasterViewController.class, "add", AddViewController.class).
               withLink(EditViewController.class, "save", MasterViewController.class).
               withTaskAction(MasterViewController.class, "remove", RemoveActionTask.class).
               withTaskAction(MasterViewController.class, "load", LoadPersonsTask.class).
               withAction(AddViewController.class, "save", new FlowActionChain(new FlowMethodAction("addPerson"), new FlowLink<MasterViewController>(MasterViewController.class)));

A action chain defines a list of actions that will be handled. In this example the “save” button is bound to an action chain that first calls the “addPerson” method and then links to the master view. By doing so new persons can be created.
Next to all the action types that are shown in this example DataFX will provide additional ones and the ability to add custom action classes.
As a last step we want to add validation. When a new person is created we want to check if the name is not null. The DataFX API supports the default Java Bean Validation and adds to support for JavaFX properties. Because of this we can easily add a NotNull annotation to the name property:

@NotNull
private StringProperty nameProperty = new SimpleStringProperty();

To validate the data of the view a validation action can be added to the action chain that is bound to the “save” button:

Flow flow = new Flow(MasterViewController.class).
               ...
               withAction(AddViewController.class, "save", new FlowActionChain(new ValidationFlowAction(), new FlowMethodAction("addPerson"), new FlowLink<MasterViewController>(MasterViewController.class)));

The validation action automatically validates all validatable fields that are defined in the controller. Groups, as defined in the Java Bean Valdidation, are supported, too. When any data is not valid the action chain will stop.
To provide feedback to the user some additional code is needed. The validator can be injected to the controller:

@Validator
private ValidatorFX<AddViewController> validator;

Now we can add a event handler to the validator that will show violations on screen:

@FXMLController("detailView.fxml")
public class AddViewController {
 
...
 
 @FXML
 private Label violationLabel;
 @Validator
 private ValidatorFX<AddViewController> validator;
 
 
 @PostConstruct
    public void init() {
        ...
        validator.setOnValidationFinished(event -> handleViolations(event.getViolations());
    }
    private void handleViolations(Set<ConstraintViolation<AddViewController>> violations) {
        if(violations.isEmpty()) {
            violationLabel.setVisible(false);
        } else {
            ConstraintViolation<AddViewController> violation = violations.iterator().next();
            violationLabel.setText(violation.getPropertyPath() + " " + violation.getMessage());
            violationLabel.setVisible(true);
        }
    }
}

Once this is done the view will show violations on the screen:
datafx6
This example shows some of the DataFX Controller features. The complete API is not finished yet and can be found in a branch of the DataFX repository. I hope to receive some feedback about this example.

JavaFX at JavaOne

JavaOne 2013 was loaded with numerous awesome JavaFX talks. Thanks to Parleys you can watch most of the talks online. I created a list of all JavaFX related talks that have been released on Parleys until now.

Let’s Get Wet! AquaFX and Best Practices for Skinning JavaFX Controls
by Claudine Zillmann and Hendrik Ebbers

DataFX: The Best Way to Get Real-World Data into Your JavaFX Application
by Johan Vos and Hendrik Ebbers

The Implementation of a Digital Task Board for Distributed Scrum with JavaFX
by Alexander Casall

The JavaFX API’s Synergy with JavaFX 3D
by Aleksandr Kuznetcov and Joseph Andresen

GroovyFX: Making JavaFX Groovy
by Dierk Koenig

JavaFX for the Enterprise with OpenDolphin
by Dierk Koenig

Taking a Leap Forward with JavaFX
by Simon Ritter and Gerrit Grunwald

Optimizing JavaFX Applications
by Oleg Mazurov

OpenJFX: State of the Union
by Stephen Northover and Richard Bair

JavaFX in the Wild: Putting a Great Face on Java Industrial Applications
by José Pereda

Modeling, Texturing, and Lighting Mesh Geometry in JavaFX 3D
by John Yoon

All the Nodes That Are Fit to Print: A Tour of the New JavaFX Printing APIs
by Jennifer Godinez and Philip Race

JavaFX 3D: The Third Dimension
by Kevin Rushforth and Chien Yang

Be Creative and Create Your Own JavaFX 8 Controls
by Gerrit Grunwald

Building Rich Visual Tools in Java
by Sven Reimers, Zoran Sevarac and Jaroslav Tulach

CSS Gold Nuggets
by Jasper Potts

Ten Ways to Make Your JavaFX App Shine
by Martin Gunnarsson and Pär Sikö

Of Raspberries, Dolphins, and Chickens: Visualizing Embedded Data with JavaFX
by Gerrit Grunwald and Todd Costella

JavaFX: Tools of the Trade
by Andres Almiray and IX-CHEL RUIZ

“Use the Force, Luke” or Tips and Tricks for Using the Capabilities of JavaFX
by Gerrit Grunwald

Advancements in Text and Internationalization for JavaFX 8
by Felipe Heidrich

Making Your JavaFX Application Fly on the Raspberry Pi
by David Hill

Truly Native Java Apps on iOS with RoboVM
by Niklas Therning

Scratching the Surface with JavaFX
by James Weaver

Developing Rich Interfaces in JavaFX for Ultrabooks
by Stephen Chin, Bruno Borges and Felipe Pedroso

Beyond Beauty: JavaFX, Parallax, Touch, Raspberry Pi, Gyroscopes, and Much More
by Angela Caicedo

Building and Deploying JavaFX Applications with Gradle or Maven (or Ant!)
by Danno Ferrin

Ten Man-Years of JavaFX: Real-World Project Experiences
by Henrik Olsson

Productive UI Design with JavaFX Scene Builder
by Moises Chicharro

Integrating JavaFX with Native Technologies
by Felipe Heidrich and Stephen Northover

Simplify your app by using Bonjour

If you are writing a JavaFX application that will connect to different servers in a local network you should have a look at Bonjour / ZeroConf. This technology is for example used by Apple to implement Airplay. If you want to stream pictures from your iPhone to a appleTV you need no configuration. The iPhone will find the picture service in the local network automatically. This can be very helpful for home automation and other embedded systems. I prepared some slides for a Bonjour talk at Java User Group Dortmund, Germany and uploaded them to our slide archive at guigarage.