JavaFX 1.2 asynchronous chat client

A couple of months ago, I wrote a JavaFX chat client using JavaFX 1.1 --- see my previous blog entry. The article below describes the changes that are needed to port this chat client to JavaFX 1.2.

The main difficulty in the JavaFX 1.1 chat client was to get the asynchronous stuff working: we have an open connection towards the chatserver, and new chatentries from all clients are pushed through this connection to the JavaFX client. Clearly, we cannot block the Event Dispatching Thread for achieving this. Starting a new Thread in JavaFX and realizing a non-blocking communication between this thread and the EDT was not trivial in JavaFX 1.1, but the chat client that was discussed in my old blog entry did the job.

The changes between JavaFX 1.1 and JavaFX 1.2 are described here and indeed, the asynchronous functionality has changed considerably. Some general information about the JavaFX 1.2 Async model can be found in this blog entry from Baechul. In short, the most important changes are:

javafx.async.AbstractAsyncOperation disappeared, and javafx.async.JavaTaskBase is introduced

a RunnableFuture interface is introduced.

The architecture

The core idea that I used in the ChatClient, is still valid in JavaFX 1.2: a JavaFX class is used to create an instance of a Java thread, and this thread contains a backpointer to the JavaFX model.

The following diagram is therefore still valid in JavaFX 1.2:

The code

The chatclient code that works in JavaFX 1.2 is available as a NetBeans project file here. Remember that you need to run a chat-server as well, if you want to run the example. The dummy server we are using is the same as the one we use in the JavaFX 1.1 example. You can get this chatserver as a NetBeans project file as well here.

The changes

Below are the changes I had to make to my previous version of the JavaFX Chat Client in order to make it compile and run in JavaFX 1.2

The AsyncReader class extended com.sun.javafx.runtime.async.AbstractAsyncOperation in the 1. 1 version. That concept is being replaced by the javafx.async.RunnableFuture interface. Hence, we have

public class AsyncReader implements RunnableFuture

The RunnableFuture interface has a public void run() method that we should implement. In the old AbstractAsyncOperation class, the run-logic was in the call method. Instead of

public Object call() throws Exception

we now have

public void run() throws Exception

We don't have the com.sun.javafx.runtime.async.AsyncOperationListener class anymore, so the constructor for the AsyncReader simply becomes

public AsyncReader(ChatInput callback) {

this.callback = callback;

}

Note that the callback parameter is a Java interface that is implemented by the ChatHistoryBox.fx class. This allows the java class AsyncReader to call into the JavaFX class ChatHistoryBox.

Since javafx.async.AbstractAsyncOperation is more or less replaced by JavaTaskBase, the ChatReader.fx class now extends JavaTaskBase

JavaTaskBase requires a create-method. This method is called by the start() method, and it should return a RunnableFuture instance. This is more or less what we did before in the start() method of the AbstractAsyncOperation, hence we transformed the behavior of old start() method into the new create() method. The create() method creates an AsyncReader instance (a Java object implementing RunnableFuture) and returns this.

The same changes should be applied to AsyncWriter and ChatWriter

When a new textentry is received by the AsyncReader, we used the invokeLater() Swing method for notifying the EDT of changes that should be made. It is recommended to use the JavaFX.deferAction for this, though:

javafx.lang.FX.deferAction(new Function0() {

public Void invoke() {

callback.gotText(oneline);

return null;

}

});

We have to start the ChatReader by calling the start method. This is done in Main.fx, after the ChatReader has been created.

Similarly, when a new text-entry has been submitted by the user, a ChatWriter instance needs to be created and started.

Conclusion

The JavaFX 1.2 asynchronous model is not completely different from the JavaFX 1.1 model. Some com.sun specific classes have been replaced by javafx classes, which is good of course. The communication from the Java class back into the javaFX EDT, using FX.deferAction can probably be simplified in future releases.