Featured Post

Applying Email Validation to a JavaFX TextField Using Binding

This example uses the same controller as in a previous post but adds a use case to support email validation.  A Commons Validator object is ...

Sunday, February 15, 2015

Dynamic FX Application Modules - Part 1 - Overview

This is the first part of a six part series on building a Java FX application using dynamic modules.  While I could easily build this demo application using straight-up FX techniques (an Application, some FXML, some Controllers, I've seen the simplistic design become too monolithic and unwieldy for today's agile methodologies and remote project teams.  What's needed for larger efforts is a design that supports adding functionality that's decoupled in terms of logical, component, and runtime dependencies.

This decoupling allows independent and segregated module development, runtime fault tolerance through isolating modules, easier testing of standalone modules, and a logical separation of dependencies.


This screenshot shows a multi-Stage Java FX Application.  A primary Stage is created from a JavaFX Application subclass.  This is the Core screen with buttons Show A - Show D along its left side.  Buttons Show A - Show D will display other Stages.  For example, pressing Show A displays Screen A, running in a new Stage.

Buttons on a Primary Stage Launch Other Stages
Each Stage has a Scene and each Scene maps to an FXML file created in Scene Builder 2.0.  An FXML file references a Controller class.  Here are the FXML files and their related Controller classes.  homeScreen.fxml is the Core screen used by the primary Stage.

FXML Files Paired with Controller Classes

This next screenshot shows what the FXML and Controller classes look like in the IntelliJ project browser.  An FXML / Controller class pair is stored in separate package with the prefix "subapp_".  The naming convention "subapp_" denotes those packages as SubApps which is a termed coined by this project to describe a child Stage and its dependencies.  For now, focus on the FXML and Controllers.  Later sections will describe the Module and ServiceObject classes.

IntelliJ Project Structure Showing Grouping of FXML and Controller Classes

The app_core package looks similar to the subapp_ packages, but it is not part of the dynamic loading.  app_core forms a kernel that will be run unconditionally.

At this point, I have FXML and Controller classes grouped in packages.  All of this can be pulled together in a static fashion (no dynamic loading).  I could make HomeScreenController aware of the contents of the subapp_* packages' FXML and Controller, creating buttons for each subapp_* package.  I would then provide a handler for each button that would create the objects in a subapp_* package.  My terminology and package design aside, you've done something similar if you've coded an FX app.


By breaking the project up into packages, I've shown a good logical design.  This helps keep code focused for developers browsing the codebase.  Also, packages help to decrease coupling and increase information hiding, particularly where package-level access is used. 

The logical structure is shown in the following package diagram.  A toplevel Main class initializes app_core, starting with HomeScreenController.  app_core contains a discovery mechanism, but does not explicitly refer to any of the other modules.  The inverse relationship is different, the other modules do know of app_core which provides shared services.  There is a framework package that is off to the side, this is a common library known to all classes.

SubApps Know About Core, but Core Doesn't Know About SubApps
Notice in the diagram and also in the preceding IntelliJ screenshot that subapp_d is not in the same project as the rest of the classes.  This is key to the presentation.  I can develop a SubApp in complete isolation of the rest of the code and deliver it where it will be discovered automatically at runtime and made available.  Here is a second IntelliJ screenshot showing where subapp_d lives.

SubApp D is Completely Separate from the Rest of the Project

Being able to segregate components and development out in this way is helpful on a number of fronts:
  • Fault Tolerance,
  • Intellectual Property, and
  • Platform Stability.
Firstly, for the developer responsible for the overall app, problem SubApps can be isolated without fear of bringing down the rest of the app.  If a SubApp is failing one day -- and is deployed as a separate JAR -- it can be pulled out quickly and the rest of the app can continue being used or tested.  Of course the SubApp needs to be fixed, but operating the app in a degraded state may give the users or testers enough functionality to be productive.

Secondly, for a team, the business might not want every developer having access to a full set of source code.  In fact, an independent team may want to develop a module outside of a binding legal agreement.  If a team can install a single JAR and see its functionality realized, drawing off of common system services, the overall app may become more useful.

Finally, SubApps give developers rules for engagement in working with common services and initialization.  That is, a new feature doesn't require a developer to dive into a mission critical initialization code block to add their new feature. 

To build the app in Figure "Buttons on a Primary Stage Launch Other Stages" takes about 20 minutes in Scene Builder and if you're working solo, that may all you need to do.  But if you're confronted with a larger project -- say a porting project with 7 developers, 3k legacy files, etc -- you don't want the design to hit a wall by compiling everything together and pushing out single JAR.  Look for the next part of the series that will introduce the role of dependency injection in the Dynamic SubApps.

Click Dynamic FX Application Modules - Part 2 - Foundation - Google Guice for the next part of the series.

No comments:

Post a Comment