Introducing...

Getting real world data into Java UI Controls with DataFX

JohanVos
Javafx.1

Johan Vos introduces us to the DataFX project, making JavaFX go beyond its regular functionality.

From December’s
JAX Magazine
, Johan Vos introduces the DataFX project, making JavaFX go
beyond its regular functionality.

JavaFX is a powerful technology for the interactive rendering of
information on a large and growing number of client devices
(desktop, laptop, tablet, phone, embedded). The JavaFX 2.2 API’s
contain a whole set of functionality that allows developers to use
different UI controls, with lots of emphasis on today’s
requirements for user interfaces: charts, animations, CSS-styling.
In a typical business application, the JavaFX client needs to
communicate with a back-end system in order to get or send data
from UI controls to backend systems. The open-source DataFX project
is exactly about this.

In a typical business application, the JavaFX client needs to
communicate with a back-end system in order to get or send data
from UI controls to backend systems. The open-source DataFX project
is exactly about this.

Taking advantage of JavaFX

DataFX consists of two parts. One part focusses on Control Cell
Factories, making it easy to view and edit data in the typical
JavaFX Controls (ListView, TableView). A number of the Control Cell
Factories that are currently in JavaFX 2.2 originated in DataFX.
The other part is about adapters for getting content into JavaFX
Controls. This article will discuss the second part.

Today, most webservices make their data available in either XML
or JSON format via REST-based services. The DataFX datasources make
it easy to obtain this data and populate UI Controls with it. Two
important characteristics of the JavaFX platform are leveraged by
DataFX:

  • Asynchronous
    processing
    .
    When developing interactive client-applications, it is important to
    keep the user interface highly responsive, even when background
    tasks are consuming lots of resources. The JavaFX platform provides
    the Service and Task classes in the javafx.concurrent package that
    allow for asynchronous processing. However, when the result of a
    processing task might lead to a change in the user interface, that
    particular change should be performed on the JavaFX Application
    Thread. As a consequence, developers should be very careful about
    what should be done and what should not be done on the JavaFX
    Application Thread. DataFX abstracts this complexity, as it will
    perform the retrieval and parsing of the data in a background
    thread, while notifying the ObservableValue object holding the
    result on the JavaFX Application Thread.

  • ObservableValue and
    ObservableList
    .
    In some cases, obtaining and parsing data is a fast process, and
    the end-user might not even notice that the data is being received.
    In many real-world scenarios, however, data is retrieved over a
    network connection at a lower speed. The time difference between
    the arrival of the first data pieces and the last ones is often
    more than a second. In case some data is already available, it
    makes sense to already present this data to the user. DataFX takes
    advantage of the JavaFX concepts of ObservableValue, and more
    particular ObservableList in order to achieve this. Once some data
    is available, DataFX will push that on the ObservableList holding
    the resulting data. The JavaFX UI Controls that use an
    ObservableList to store internal data leverage this functionality
    as well. There is no need for the developer to redraw the JavaFX UI
    Control when new data is available, as the Control will do whatever
    is necessary to visualize data when new data is added to the
    internal ObservableList.

While DataFX supports a number of protocols, we will only
describe its ability to retrieve XML and JSON based data from REST
services.

Obtaining and parsing data

The process of populating UI controls with external data can be
split into two tasks:

  1. Obtain the data, regardless where it comes from. Data can
    originate from a database, a file, a remote webservice,…

  2. Parse the data, and make it available in a format accepted by
    the JavaFX UI Controls.

Creating a request

A request to a REST endpoint at
http://your.host/some/specific/path is created by using a
RestRequestBuilder:

 

RestRequestBuilder rrb = new RestRequestBuilder("http://your.host");

 

The RestRequestBuilder allows the builder pattern to be used,
and commands can easily be concatenated. The path segments are
added by calling the path() method:

 

rrb.path("some").path("specific").path("path");

 

This can also be achieved with a single call:

 

rrb.path("some/specific/path");

 

By default, DataFX will use the HTTP GET protocol to retrieve
data from the endpoint. This can be overridden by calling the
method method:

 

rrb.method("POST");

 

Depending on the request method, query parameters or form
parameters can be supplied. Specifying query parameters is done
via:

 

rrb.queryParam("key1", "value1");

rrb.queryParam("key2", "value2");

 

Similarly, form parameters are specified via:

 

rrb.formParam("key1", "value1");

rrb.formParam("key2", "value2");

 

Finally, a RestRequest is created using the build() method:

 

RestRequest restRequest = rrb.build();

 

Obtaining data from a request

Incoming data from requests can be parsed using an
ObjectDataSource. The ObjectDataSource will parse the incoming data
into Java Objects that can be used to populate JavaFX UI Controls.
These Java Objects can be regular POJO’s with getters and setters,
or they can leverage JavaFX Properties.

Developers can directly create an ObjectDataSource and
manipulate it, or they can use an ObjectDataSourceBuilder,
customize it, and build an ObjectDataSource.

An ObjectDataSourceBuilder is easily created:

 

ObjectDataSourceBuilder odsb = new ObjectDataSourceBuilder();

 

The ObjectDataSourceBuilder needs to know where the incoming
data can be obtained. A DataSourceReader holding the incoming data
needs to be specified. In the previous paragraph, we created a
RestRequest (which implements DataSourceReader), and this one is
passed into the ObjectDataSourceBuilder as follows:

 

odsb.dataSourceReader (restRequest);

 

The ObjectDataSourceBuilder needs to know the format of the data
in order to be able to process it. Currently, JSON and XML are
supported. Specifying the format is achieved as follows:

 

odsb.format(Format.XML);

 

In case we want to populate a JavaFX ListView or a TableView,
the data will be parsed into an instance of ObservableList. It is
good practice to first create this instance, pass it to the
ListView or

TableView, and then start populating it. In case of a ListView,
this would be done using the following snippet:

 

final ObservableList<Foo> listItems = FXCollections.observableArrayList();

ListView<Foo> listView = new ListView(listItems);

odsb.resultList(listItems);

 

When the resultList method is called on the
ObjectDataSourceBuilder, all parsed entries will be added to the
ObservableList instance that is passed. If the original list is
non-empty, parsed entries will be added after the existing
entries.

In the case of an incoming JSON stream where the input consists
of a number of array elements, it is clear that those elements
correspond to the different entries in the stream. In other cases,
DataFX needs to know how the different entries in an incoming
datastream are separated – e.g. by means of an XML element name or
a JSON key. The separator is specified using:

 

odsb.itemTag("myElementName");

 

The primary usage for the ObjectDataSource in DataFX is to
populate JavaFX UI controls, but it can be used for asynchronous
REST requests in general. In case we want the incoming result to be
assigned to a single object rather than to a list, the resultObject
method can be used:

 

ObjectProperty<T> myTarget;

...

odsb.resultObject(myTarget);

 

In this case, the incoming data will be parsed into an instance
of class <T>. In some cases – e.g. when sending data to an
endpoint without expecting data back, the ObjectDataSource needs to
be instructed not to wait for resulting data. This is done as
follows:

 

odsb.noResult(true);

 

Finally, when the ObjectDataSourceBuilder is created and
configured, the ObjectDataSource can be created:

 

ObjectDataSource ods = odsb.build();

 

The real retrieval and parsing of the data is done by calling
the retrieve method on the ObjectDataSource:

 

Service service = ods.retrieve();

 

Once this method is called, data will be obtained and parsed,
and in case the resultList is set to an ObservableList that is used
in a ListView, the ListView will be populated as soon as data is
available.

Since the result object of
the retrieve call is an instance of javafx.concurrent.Service, the
caller can follow the status of the retrieval process by listening
for changes on the state property of the Service as seen in

Listing
1
.

Listing 1

retrieve.stateProperty().addListener(new ChangeListener<State>() {
    @Override
    public void changed(ObservableValue observable, State oldValue, State newValue) {
       System.out.println("state changed from " + oldValue + " to " + newValue);
    }
  });

 

Conclusion

In this article, we briefly
described the goals of DataFX, and illustrated the usage based on a
common pattern: render data available in webservices using JavaFX
UI Controls. There are many more options and possibilities
available, refer to the following resources in the references. You
can visit the official DataFX
website
 while t
he code, mailing lists and issue tracker can be found at
Java.net
. DataFX is available in the central maven
repository, with groupId org.javafxdata and artifact id
datafx-core. More information on how to create a JavaFX Maven
project leveraging DataFX can be found in this blog
entry
.

Author
Bio

Johan Vos started working with Java in 1995, as part of his
PhD research. He joined the Blackdown team and ported Java 1.2 to
Linux/SPARC. Johan has been a Java consultant ever since, and
worked for a number of companies (e.g. The Reference, Acunia). He
co-founded LodgON, where the main focus is on social networking
software and recently became a Java Champion. He was part of the
Core Platform Expert Group of OSGi that created the OSGi platform
specifications. His main technology interests are currently
GlassFish and JavaFX. He holds an Msc in civil engineering (mining)
and a PhD in Applied Physics.

This tutorial originally appeared in JAX Magazine –
TomEE. For that issue and others, click here.

Author
JohanVos
Johan Vos started working with Java in 1995, as part of his PhD research. He joined the Blackdown team and ported Java 1.2 to Linux/SPARC. Johan has been a Java consultant ever since, and worked for a number of companies (e.g. The Reference, Acunia). He co-founded LodgON, where the main focus is on social networking software and recently became a Java Champion. He was part of the Core Platform Expert Group of OSGi that created the OSGi platform specifications. His main technology interests are currently GlassFish and JavaFX. He holds an Msc in civil engineering (mining) and a PhD in Applied Physics.
Comments
comments powered by Disqus