Best Practices for JavaFX 2.0 Enterprise Applications (Part One)

By James L. Weaver

This article, which is part one of a two-part series, focuses on using best practices for developing enterprise applications in JavaFX 2.0. 

Published April 2012

Downloads:

Download: Java FX

Download: NetBeans IDE

Download: Sample Project(ZIP)

Introduction

JavaFX 2.0 is an API and runtime for creating Rich Internet Applications (RIAs). JavaFX was introduced in 2007, and version 2.0 was released in October 2011. One of the advantages of JavaFX 2.0 is that the code can be written in the Java language using mature and familiar tools.

This article, which is part one of a two-part series, focuses on using best practices for developing enterprise applications in JavaFX 2.0. 

Overview of the TweetBrowser Application

To illustrate some best practices for enterprise application development in JavaFX 2.0, a sample application named TweetBrowser will be examined. As shown in Figure 1, this application contains the following:

  • A Toolbar containing a TextField and a couple of Button controls for searching and navigating tweets obtained from the Twitter REST API.
  • A ListView whose cells contain representations of the tweets. Each tweet is represented by a subclass of ListCell that contains an ImageView for the profile picture and Hyperlink controls that enable the user to navigate to screen names, hashtags, and Web links.
  • A ProgressIndicator that spins when a search is performed and a WebView that displays the Web page associated with a Web link in a tweet.

The TweetBrowser project, which you'll download in the next section, contains the code for this application, portions of which we’ll highlight during the course of this article.

Figure 1: Screen Capture of the TweetBrowser Application at Startup

Figure 1: Screen Capture of the TweetBrowser Application at Startup

When you click a #hashtag or @screenname, a spinning progress indicator, as shown in Figure 2, appears in the upper right corner of the UI indicating that a search is in progress. You can also type a #hashtag, @screenname, or word in the text field and press the Enter key or click the Search button. Either way, the Search button’s appearance changes to an X to indicate that you can cancel the search by clicking the button, and most of the UI is disabled.

Figure 2: Screen Capture of TweetBrowser During a Search

Figure 2: Screen Capture of TweetBrowser During a Search

Clicking a Web link in a tweet opens a pop-up window that contains a WebView with the chosen page, as shown in Figure 3.

Figure 3: A WebView After Clicking a Hyperlink

Figure 3: A WebView After Clicking a Hyperlink

Obtaining and Running the TweetBrowser Project

  • Download the NetBeans project file, which includes the TweetBrowser project.
  • Expand the project into a directory of your choice.
  • Start NetBeans, and select File -> Open Project.
  • From the Open Project dialog box, navigate to your chosen directory and open the TweetBrowser project, as shown in Figure 4. If you receive a message stating that the jfxrt.jar file can't be found, click the Resolve button and navigate to the rt/lib folder subordinate to where you installed the JavaFX 2.0 SDK.

Note: You can obtain the NetBeans IDE from the NetBeans site.

Figure 4: Opening the TweetBrowser Project in NetBeans

Figure 4: Opening the TweetBrowser Project in NetBeans

  • To run the application, click the Run Project icon on the toolbar, or press the F6 key. The Run Project icon looks like the Play button on a media (for example, DVD) player, as shown in Figure 5.

Figure 5: Running the TweetBrowser Program in NetBeans

Figure 5: Running the TweetBrowser Program in NetBeans

The TweetBrowser application should appear in a window, as shown previously in Figure 1. Go ahead and play with the application, navigating screen names, hashtags, and Web links. We’ll analyze the application and walk through some code next.

Analyzing the TweetBrowser Application

Before diving into the code, let’s analyze the pieces shown in Figure 6, which comprise the TweetBrowser application.
Figure 6: Diagram of the TweetBrowser Application

Figure 6: Diagram of the TweetBrowser Application

Starting from the top-right of Figure 6, the TweetBrowser home page is where the user launches the application by clicking the bug-eyed bird icon. This causes the application to be invoked via Java Web Start if an instance of TweetBrowser isn’t already running. Please refer to the “See Also” section for the URL of the TweetBrowser home page.

At the bottom left of Figure 6 is a representation of the tweetbrowser.ui package, which contains two Java classes and a JavaFX cascading style sheet (CSS):

  • TweetBrowserMain is the main class of our JavaFX application, extending Application and containing main() and start() methods. Its role in the TweetBrowser application is to create a scene and populate it with the ToolBar and ListView shown in Figure 1. In addition, TweetBrowserMain creates and conditionally shows the pop-up window that contains the WebView seen previously in Figure 3.
  • TweetCell is a class that extends ListCell and renders the representation of a tweet, as shown in Figure 1. There is one TweetCell for each tweet, and the TweetCell instances are contained by the ListView.
  • tweetbrowser.css is a JavaFX CSS that styles various nodes in the application, including the Back and Search buttons and the screen name of the user that authored a tweet.

At the bottom center of Figure 6 is a representation of the tweetbrowser.model package, which contains three Java classes:

  • TweetBrowserModel is the primary model class of the application, and it contains properties that represent the state of the application. It also contains methods that utilize the REST/FX library, shown in the lower-right corner of Figure 6, to query the Twitter API. REST/FX is a library external to JavaFX 2.0, leveraged here for communicating with the Twitter REST endpoints and parsing its JSON responses. The “See Also” section at the end of this article has a link to the REST/FX project.
  • Tweet is a class that represents a tweet and follows the conventions prescribed for JavaFX properties. For example, Tweet contains a StringProperty named id that is accessible via the setId(), getId(), and idProperty() methods.
  • HistoryStack implements a FIFO stack, managing the navigation history of hashtags, words, and screen names. The Back button uses this history to determine which hashtag, word, or screen name to display when it is clicked.

As indicated in Figure 6, classes in the tweetbrowser.ui package invoke methods of classes in the tweetbrowser.model package. In addition, classes in the tweetbrowser.ui package render the state of the model to the UI, largely by utilizing the binding capabilities of JavaFX.

Techniques and Best Practices Used in the TweetBrowser Application

Some techniques and best practices used in the TweetBrowser application will be discussed in this section, namely the following:

  • Invoking an application via Java Web Start from the application’s home page
  • Ensuring only one instance of the application is started
  • Binding the UI to the model

We’ll start out with the first item in the list: invoking the application via Java Web Start from an application’s home page.

Invoking an Application via Java Web Start from the Application’s Home Page

One of the attractive features of browser-based applications is that they are instantly available at given Web pages. Users have come to expect this, so one way to increase the comfort level of a user who is accessing a rich-client Java application is to offer a Java Web Start link on a Web page. In this way, the user experience can be very similar to running a Web application, because clicking an icon opens a window that contains the application. From the user perspective, the new window contains the application, without regard to the type of window it is (a browser window or a Java application window). 

Listing 1 shows the HTML and JavaScript source for the TweetBrowser application home page, modified from the output of building the TweetBrowser project in NetBeans. 

<html><head>

<script src="http://java.com/js/dtjava.js"></script>

<script>

    function launchApplication(jnlpfile) {

        dtjava.launch(            {

                url : 'TweetBrowser.jnlp'},

            {

                javafx : '2.0+'

            },

            {}

        );

        return false;

    }

</script>

</head>

<body style="font-family: Arial; font-size: 12pt;">

  <h2 >TweetBrowser Home Page</h2>

  <a href='#'><img title="Launch TweetBrowser app"

     src="img/tweetbrowser-logo-100.png"

     onclick="return launchApplication('TweetBrowser.jnlp');"/></a>

  <p>Click the icon to launch TweetBrowser via Java Web Start</p>

</body></html>

Listing 1: Example HTML and JavaScript Code for an Application Home Page

Listing 2 contains example source code for the Java Network Launching Protocol (JNLP) that launches the TweetBrowser application, also modified from the output of building the TweetBrowser project in NetBeans. 

<?xml version="1.0" encoding="utf-8"?>

<jnlp spec="1.0" xmlns:jfx="http://javafx.com" href="TweetBrowser.jnlp">

  <information>

    <title>TweetBrowser</title>

    <vendor>Jim Weaver</vendor>

    <description>Sample JavaFX 2.0 application.</description>

    <offline-allowed/>

  </information>

  <resources os="Windows" arch="x86">

    <jfx:javafx-runtime version="2.0+"

    href="http://download.oracle.com/otn-pub/java/javafx/...code omitted..."/>

  </resources>

  <resources os="Windows" arch="x64">

    <jfx:javafx-runtime version="2.0+"

    href="http://download.oracle.com/otn-pub/java/javafx/...code omitted..."/>

  </resources>

  <resources>

    <j2se version="1.6+" href="http://bit.ly/xyGWeN"/>

    <jar href="TweetBrowser.jar" size="49305" download="eager" />

    <jar href="lib/restfx-1.0.jar" size="49092" download="eager" />

    <jar href="lib/restfx-server-1.0.jar" size="6884" download="eager" />

  </resources>

  <jfx:javafx-desc  width="800" height="600"

    main-class="javafxpert.tweetbrowser.ui.TweetBrowserMain" 

    name="TweetBrowser" />

  <update check="background"/>

</jnlp>

Listing 2: Example Code for the JNLP That Launches the Application

The main difference between the source code generated by NetBeans and the source code shown in Listings 1 and 2 is that the applet-related code has been removed, making TweetBrowser available exclusively via Java Web Start.

Please refer to the Deploying JavaFX Applications guide mentioned in the “See Also” section for a detailed explanation of how to launch JavaFX applications via Java Web Start.

Ensuring Only One Instance of the Application Is Started

One consideration in using the Java Web Start approach is ensuring that only one instance of the application is invoked, regardless of whether the user clicks the application icon when an instance is already running. To accomplish this, the TweetBrowser application leverages some classes in the javafx.jnlp package, as shown in the start() method of TweetBrowserMain.java shown in Listing 3:

  @Override public void start(final Stage primaryStage) {

    stage = primaryStage;

    try {

      singleService =

          (SingleInstanceService)ServiceManager

          .lookup("javax.jnlp.SingleInstanceService");

      singleListener = new SingleInstanceListener() {

        @Override public void newActivation(String[] params) {

          System.out.println("TweetBrowser instance already running");

          primaryStage.toFront();

        }

      };

      if (singleService != null) {

          singleService.addSingleInstanceListener(singleListener);

      }

    }

    catch (UnavailableServiceException use) {

      singleService = null;

      System.out.println("Single instance service not loaded");

    }

    primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {

      @Override public void handle(WindowEvent e) {

        if (singleService != null) {

          singleService.removeSingleInstanceListener(singleListener);

        }

      }

    });

    Scene scene = SceneBuilder.create()

      .width(1000)

      .height(660)

      .stylesheets("javafxpert/tweetbrowser/ui/tweetbrowser.css")

      .root(

        BorderPaneBuilder.create()

          .top(createToolBar())

          .center(createListView())

          .build()

      )

      .build();

    listView.disableProperty().bind(TweetBrowserModel.instance

        .queryActive.or(TweetBrowserModel.instance.webViewPopupVisible));

    invokeSearch(FIRST_SEARCH_TERM, true);

    createWebViewPopup();

    progressIndicator.visibleProperty()

                     .bind(TweetBrowserModel.instance.queryActive

                     .or(TweetBrowserModel.instance.webViewPopupWebEngine

                     .getLoadWorker().runningProperty()));   

    stage.setScene(scene);

    stage.setTitle("Tweet Browser");

    stage.show();

}

Listing 3: The TweetBrowserMain.java start() Method

If the user attempts to start the application when a instance that was started via Java Web Start is already running, the overridden newActivation() method of the SingleInstanceListener is invoked rather than starting another instance of TweetBrowser. To clean up when the application is closing, the setOnCloseRequest() method of the primary window is supplied an event handler that removes the SingleInstanceListener.

Note: To satisfy the compiler, the jnlp.jar file is used in the project at compile time, but the javafx.jnlp classes shown in Listing 3 are available at runtime by the Java deployment toolkit.

Binding the UI to the Model

Using the model/view/controller, or MVC, pattern has been a common practice in software development for many years. The JavaFX API facilitates the MVC pattern by providing the capability of binding properties of the UI to properties in the model.

As shown in Listing 4, the TweetBrowser application instantiates, and provides a reference to, the primary model class named TweetBrowserModel.

public class TweetBrowserModel {

public static TweetBrowserModel instance = new TweetBrowserModel();

public BooleanProperty queryActive = new SimpleBooleanProperty(false);

public BooleanProperty webViewPopupVisible =

                                     new SimpleBooleanProperty(false);

public ObservableList allTweets = FXCollections.observableArrayList();

...

}

Listing 4: Instantiating and Referencing the Model

This reference is used in the TweetBrowserMain and TweetCell classes to bind the UI to the model. For example, the visibleProperty of progressIndicator in Listing 3 is bound to an expression involving the queryActive property of the model in Listing 4.

Another example of binding the UI to the model is shown in Listing 5, where the items property of listView is bound to the allTweets ObservableList in Listing 4. 

  private Node createListView() {

    listView = ListViewBuilder.create()

      .items(TweetBrowserModel.instance.allTweets)

      .editable(false)

      .build();

    listView.setCellFactory(new Callback<ListView<Tweet>, ListCell<Tweet>>() {

      @Override

      public ListCell<Tweet> call(ListView<Tweet> list) {

        ListCell tweetCell = new TweetCell();

        tweetCell.setEditable(false);

        return tweetCell;

      }

    });

    return listView;

}

Listing 5: The TweetBrowserMain.java createListView() Method

Note that the binding behavior is built in to the items property of the ListView control, so the bind method isn’t used in this case.

Conclusion

Implementing techniques such as invoking an application via Java Web Start from the application’s home page, ensuring only one instance of the application is started, and binding the UI to the model make life easier for both the user and the developer. 

In part two of this series, we’ll explore more techniques and best practices used in the TweetBrowser example application.

See Also

About the Author

James L. (Jim) Weaver is a Java and JavaFX developer, author, and speaker with a passion for helping rich-client Java and JavaFX become preferred technologies for new application development. Books that Jim has authored include Inside Java, Beginning J2EE, and Pro JavaFX 2.  His professional background includes 15 years as a systems architect at EDS, and the same number of years as an independent developer. As an Oracle Java Evangelist, Jim speaks internationally at software technology conferences, including the JavaOne conferences in San Francisco and São Paulo. Jim blogs at http://javafxpert.com, tweets @javafxpert, and may be reached at james.weaver AT oracle.com.