Angular shitstorm: What's your opinion on the controversial plans for Angular 2.0?
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 the 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