tentackle-fx-rdc — Rich Desktop Client¶
Overview and Motivation¶
RDC stands for Rich Desktop Client. The tentackle-fx-rdc module is the
glue that turns the two lower layers it sits on — the
PDO layer and the
extended JavaFX layer — into a
ready-to-run desktop application.
Where tentackle-fx knows everything about JavaFX controls, controllers and
binding but nothing about persistence, and tentackle-pdo knows everything about
persistent domain objects but nothing about a UI, tentackle-fx-rdc is the only
module that knows about both. It answers the questions that arise as soon as a
PDO needs to be shown to and edited by a user:
- How is a PDO searched for, displayed, edited and saved through a UI?
- How does a PDO render itself in a table, a tree or a combo box?
- What happens when the user right-clicks a PDO — which context menu appears?
- How does the whole application start up, log in against a backend and shut down again?
The module is deliberately built around a small number of extension points so that an application provides only the parts that are specific to its entities, while the framework supplies the generic CRUD machinery, dialogs, background execution and lifecycle.
Design principles¶
- One coordination object per entity. Everything the UI needs to know about
a PDO type is bundled behind a single interface — the
GuiProvider. Applications implement (or partially override) it per entity; the framework discovers the implementation via the SPI mechanism. - Generic CRUD, specific views. The search-, edit- and tree machinery
(
PdoSearch,PdoCrud,PdoController, …) is entity-agnostic. The only entity-specific artifacts an application must supply are the editor view, the finder view and the table/tree configuration. - Never block the FX thread. Persistence operations may go to a local database or across the network. RDC funnels them through a background pool and marshals the results back onto the FX application thread (see Background execution).
- Location transparency, inherited. Because PDOs are remoting-capable, the
same UI code works whether the client talks to the database directly or through
a middle-tier server — no
LazyInitializationException, ever. - Convention with escape hatches. Defaults (
DefaultGuiProvider,DefaultPdoFinder,DefaultPdoEditor,DefaultRdcFactory) cover the common case; every one of them can be replaced or subclassed.
Where it sits¶
tentackle-fx-rdc ── knows PDOs *and* JavaFX ─────────────┐
│ requires transitive │
├── org.tentackle.fx (controls, controllers, │ the only module
│ binding, tables) │ that bridges the
└── org.tentackle.pdo (persistent domain │ UI and the
objects, sessions, DDD) │ persistence world
┘
The companion modules build on top of it:
| Module | Purpose |
|---|---|
tentackle-fx-rdc-poi |
Excel (Apache POI) export of RDC tables. |
tentackle-fx-rdc-update |
Application self-update / deployment support. |
tentackle-test-fx-rdc |
JUnit 5 / TestNG base classes for testing GuiProviders, controllers and table configurations. |
Key Concepts¶
GuiProvider — the per-entity hub¶
The GuiProvider<T> is the
central abstraction of the module. One GuiProvider exists per PDO type and
encapsulates all the UI behavior for that entity. Its responsibilities fall
into a few groups:
- Identity / appearance —
createGraphic()for an icon, the resource bundle (getBundle(),isBundleProvided()). - Editing —
isEditorAvailable(),isEditAllowed(),isViewAllowed(),createEditor()returning aPdoEditor<T>. - Searching —
isFinderAvailable(),createFinder()returning aPdoFinder<T>. - Drag & drop —
createDragboard(...),isDragAccepted(...),dropDragboard(...). - Tree rendering —
getTreeRoot(),getTreeText(...),getToolTipText(...),createTreeItem(),getTreeCellFactory(), and the navigation hooksgetTreeChildObjects(...)/getTreeParentObjects(...)with theirprovidesTreeChildObjects()/getTreeExpandMaxDepth()guards. - Table rendering —
createTableView().
Applications rarely implement the whole interface. They subclass
DefaultGuiProvider and
override only what differs. A provider is registered declaratively:
@GuiProviderService(Invoice.class)
public class InvoiceGuiProvider extends DefaultGuiProvider<Invoice> {
@Override
public PdoEditor<Invoice> createEditor() {
return Fx.load(InvoiceEditor.class); // an FXML controller
}
@Override
public PdoFinder<Invoice> createFinder() {
return Fx.load(InvoiceFinder.class);
}
}
The @GuiProviderService
annotation is picked up at build time by an annotation processor (see
Annotation processors) which generates the
META-INF/services entry, so the provider is found by
GuiProviderFactory at
runtime — in both modular and non-modular deployments.
Read-only views with PdoViewer¶
When an entity can be looked at but not edited, wrap a plain view controller in a
PdoViewer and disable editing:
@Override
public PdoEditor<Incident> createEditor() {
return new PdoViewer<Incident, IncidentView>(Fx.load(IncidentView.class));
}
@Override
public boolean isEditAllowed() {
return false; // grays out the "edit" context-menu item
}
Rdc and RdcFactory — the entry points¶
Rdc is a static convenience facade
(mirroring the role Fx plays in tentackle-fx) that bundles the most common
operations so calling code reads naturally. The heavy lifting is delegated to the
SPI-resolved RdcFactory
(default: DefaultRdcFactory).
Typical one-liners:
// open a modal edit dialog for a PDO
Rdc.displayCrudStage(invoice, /*editable*/ true, ownerWindow);
// open a search dialog for an entity
Rdc.displaySearchStage(on(Invoice.class), Modality.NONE, ownerWindow);
// render a PDO in a tree
Rdc.showTree(owner, rootPdo);
// build cells / tree items for a table or tree
TreeItem<Invoice> item = Rdc.createTreeItem(invoice);
Rdc also exposes the standard save / discard / cancel dialog
(showSaveDiscardCancelDialog), stage-hierarchy helpers
(closeStageHierarchy) and the background-execution helpers described below.
CRUD controllers: PdoController, PdoCrud, PdoSearch¶
The generic editing machinery is layered:
| Type | Role |
|---|---|
PdoController<T> |
Base FX controller bound to a single PDO (setPdo). |
PdoEditor<T> |
A controller that edits a PDO; supplied by the GuiProvider. |
PdoFinder<T> |
Holds the search-criteria view and runs the query. |
PdoCrud<T> |
The full create/read/update/delete controller wrapping an editor with toolbar, navigation and persistence actions. |
PdoSearch<T> |
The search controller wrapping a finder with a result table that opens CRUD on selection. |
The default finder,
DefaultPdoFinder,
provides a normtext search field when the entity defines a normtext, and
otherwise selects all PDOs immediately — so even an entity with no custom finder
view is searchable out of the box.
Tables, trees and cells¶
RDC plugs PDOs into the table and tree infrastructure of tentackle-fx:
PdoTableCell,PdoTreeCellandPdoTreeTableCellrender a PDO using the text/graphic supplied by itsGuiProvider.PdoTreeItemlazily expands a tree by asking the provider for child/parent objects, honouringgetTreeExpandMaxDepth()andstopTreeExpansion().- The
tablepackage adds RDC-aware configuration (RdcTableConfiguration,RdcTableColumnConfiguration), a column-chooser/preferences popup (TablePopup) and printing (TablePrinter). - The
componentpackage contributes PDO-aware controls:RdcComboBoxandRdcChoiceBox, complete with thedelegate/buildcompanions that the fx delegate pattern prescribes.
Value translators¶
The translate package supplies ready-made
value translators
for PDOs, so a PersistentDomainObject can appear in any FX control without
boilerplate:
PdoStringTranslator— PDO ⇄ display string.PdoObservableListTranslator— a PDO collection as an observable list.PdoTreeItemTranslator/PdoCollectionTreeItemTranslator— PDOs as tree items.PdoComponentAddon— wires the above into the component build process.
Context menus¶
Right-clicking a PDO in a table or tree raises a context menu assembled by a
PdoContextMenuFactory
(default
DefaultPdoContextMenuFactory).
Menu items are themselves discoverable services, so an application can add its own
without touching the framework:
- Items implement
PdoTableContextMenuItem,PdoTreeContextMenuItemorPdoTreeTableContextMenuItemand are declared with the matching@PdoTableContextMenuItemService/@PdoTreeContextMenuItemService/@PdoTreeTableContextMenuItemServiceannotation. - The built-in items live in the
contextmenupackage:EditItem,ViewItem,ExpandItemandCollapseItem.
Events¶
PdoEvent, together with
EventListenerProxy,
notifies the UI about persistence operations (save, delete, …) on a PDO so that
open views, tables and trees can react and refresh.
Background execution¶
Persistence calls must never run on the JavaFX application thread. RDC provides
the bg(...) helpers on Rdc (backed by
RdcUtilitiesWithBackgroundPool)
to run work off-thread and post the result back:
Rdc.bg(node,
() -> invoice.reload(), // runs in background pool
reloaded -> refreshView(reloaded), // runs on the FX thread
ex -> showError(ex)); // FX thread, on failure
This pattern keeps the UI responsive regardless of whether the PDO is served locally or remotely.
Application lifecycle (app, login)¶
The app and login packages turn the building blocks above into a complete,
launchable application.
FxApplication— the base class for any Tentackle FX application.LoginApplication— usually the application that is launched first. It shows the login view and spawns the login handler; on success it hands over to the real application.DesktopApplication<C>— the main desktop application, parameterized by its main controller type.LoginFailedHandlerandLogoutEventHandler— pluggable handlers for the corresponding lifecycle events.
The login package implements the login flow:
Login (the controller),
LoginController (the
interface that lets an application substitute its own login view) and
Backends (add / edit /
remove the server backends the user can connect to).
A minimal startup therefore looks like:
launch LoginApplication
└─ user picks a Backend and authenticates (login package)
└─ on success → DesktopApplication starts with the main controller
└─ controllers use Rdc / GuiProvider to search, view and edit PDOs
Security and administration¶
- The
securitypackage provides a UI for editing the PDO security rules enforced by the persistence layer:SecurityEditor,SecurityRulesView, and aSecurityDialogFactory(defaultDefaultSecurityDialogFactory). Security thus participates in the same per-aggregate model described in the PDO documentation. - The
adminpackage contains operational views, e.g.SessionsViewfor monitoring live sessions on the server.
Annotation processors (apt)¶
To keep service discovery working in both modular (JPMS) and classpath
deployments, the apt package provides validators to ensure the contracts.
GuiProviderServiceAnnotationProcessor— for@GuiProviderService.PdoTableContextMenuItemServiceAnnotationProcessor/PdoTreeContextMenuItemServiceAnnotationProcessor— for the context-menu item service annotations.
How It Fits Together¶
A typical "open an entity for editing" flow ties the pieces together:
- The user triggers an action (menu, button, double-click in a table).
- Calling code asks
Rdcfor the operation, e.g.Rdc.displayCrudStage(pdo, true, owner). RdcFactoryresolves theGuiProviderfor the PDO's type viaGuiProviderFactory.- The provider creates a
PdoEditor(an FX controller fromtentackle-fx), whichPdoCrudwraps with toolbar, navigation and persistence actions. - The editor's controls are bound to the PDO's attributes; edits flow through the binding layer.
- On save,
PdoCrudrunspdo.save()viaRdc.bg(...)off the FX thread; on completion aPdoEventrefreshes any other open views.
The application only had to supply an editor view (or even use a generated default)
and a GuiProvider; everything else came from the framework.
Package Reference¶
| Package | Contents |
|---|---|
org.tentackle.fx.rdc |
Core: Rdc, RdcFactory, GuiProvider, CRUD controllers, table/tree cells, events, utilities. |
org.tentackle.fx.rdc.app |
Application lifecycle: FxApplication, LoginApplication, DesktopApplication, lifecycle handlers. |
org.tentackle.fx.rdc.login |
Login view, controller and backend management. |
org.tentackle.fx.rdc.crud |
The generic PdoCrud create/read/update/delete controller. |
org.tentackle.fx.rdc.search |
PdoSearch and the default finder. |
org.tentackle.fx.rdc.table |
RDC table configuration, column popup, printing, table utilities. |
org.tentackle.fx.rdc.component(.delegate/.build) |
PDO-aware combo/choice boxes with their delegates and builders. |
org.tentackle.fx.rdc.translate |
Predefined PDO value translators. |
org.tentackle.fx.rdc.contextmenu |
Built-in context-menu items (edit, view, expand, collapse). |
org.tentackle.fx.rdc.security |
Security-rules editing UI. |
org.tentackle.fx.rdc.admin |
Administrative views (e.g. live sessions). |
org.tentackle.fx.rdc.apt |
Annotation processors for service registration. |
org.tentackle.fx.rdc.service |
Module hook / runtime registration. |