Quickstart¶

This chapter takes you from nothing to a running, multi-tier Tentackle application in a few minutes. The generated project is a complete starting point for a larger one: a middle-tier server, a JavaFX desktop client and a headless daemon, split into the JPMS modules that keep domain logic, persistence model and UI cleanly apart (see the Multi-Tier Cascade for how these tiers cooperate). Everything is a full JPMS (Jigsaw) build that produces jlink / jpackage images with built-in client auto-update. The server talks to PostgreSQL by default, but any relational database supported by the backend abstraction layer will do.
To understand the code you are about to generate, read about Persistent Domain Objects and the guarantees behind them in Correctness First; for a guided tour of the generated result, see the MyApp Walkthrough.
Prerequisites¶
- Java (JDK) >= 25
- Maven >= 3.9.0
- PostgreSQL >= 9
Verify with:
PostgreSQL is only needed to run the application. The generated unit tests run against an in-memory H2 database and require no setup at all (see tentackle-test-pdo).
Notice: for older LTS versions see the branches java21, java17, java11
and java8. The java21 and java17 lines still receive bugfixes; java11
and java8 reached end-of-life.
Project Setup¶
Generate your project via the Tentackle Maven archetype
(use the latest release on Maven Central
as the archetypeVersion):
mvn archetype:generate \
-DarchetypeGroupId=org.tentackle \
-DarchetypeArtifactId=tentackle-project-archetype \
-DarchetypeVersion=25.18.2.0
- groupId: the group-ID of your project.
- artifactId: the root artifact-ID. All module artifact-IDs will be prefixed by this name, separated by a hyphen (e.g.
myapp-gui). It also becomes the default database name, user and password. - version: the project's version.
- package: the Java base package.
- application: the application's name. It is used as a prefix in several Java classnames (i.e., no spaces, first letter in uppercase, etc...) and in various other places, such as window titles and the TRIP service names.
Example:
Define value for property 'groupId': com.example
Define value for property 'artifactId': myapp
Define value for property 'version' 1.0-SNAPSHOT: :
Define value for property 'package' com.example: : com.example.myapp
Define value for property 'application': MyApp
artifactId. It is a Maven reactor of eight modules plus a jlink
sub-aggregator, mirroring Tentackle's own layering:
myapp
├── myapp-common shared constants, session info, domain context, preferences
├── myapp-pdo PDO interfaces with the embedded model
├── myapp-domain domain-logic implementations
├── myapp-persistence persistence implementations + remote delegates
├── myapp-gui JavaFX controllers, editors, FXML/CSS
├── myapp-client the desktop FX client
├── myapp-server the middle-tier server
├── myapp-daemon a headless console client
└── jlink jlink/jpackage images (profile "jlink" only)
It is not just a scaffold but a small reference application — users, user groups and messages, with CRUD editors, login, security and i18n in English and German. See the Tentackle Project Archetype for what each module contains and why.
Change to the project directory and build it:
Notes:
- The profile
jlinkinstructs Maven to build the jlink and/or jpackage images as well. Without it, the build is faster but produces plain jars only — the Run section below assumes the images exist. - The build runs the complete Tentackle pipeline: the tentackle-maven-plugin registers services, the wurblets weave the generated persistence code into guarded source regions, and the SQL plugin derives the DDL from the model embedded in the PDO interfaces.
Database Setup¶
Log into postgres and create a user with the same name and password as the artifactId.
Then, create a database with the same name belonging to that user.
Example:
These are just the defaults taken from the dbUrl, dbUser and dbPasswd
properties in the generated root pom.xml — change them there if you prefer
different credentials or a different database backend.
Back on the shell, run the SQL script to create the database tables:
This script was generated by the build: the SQL plugin turned the model into backend-specific DDL. When you later change the model, the plugin generates migration scripts the same way — the model is the single source of truth for classes and schema.Next, change to the server directory and populate the database:
This runs a special TestNG group (initdb, see FillDatabase.java in the
server's test sources) against the real database instead of the in-memory H2
used by ordinary tests. It creates a
number pool for message numbers,
the ADMINS user group, and three users:
| User | Password | Purpose |
|---|---|---|
gonzo |
gonzo |
interactive login, admin |
kermit |
piggy |
a second interactive user |
daemon |
daemon |
the account the headless daemon connects with |
Only users stored this way may open a session on the middle-tier server — the example already enforces the security model.
Run¶
Start the middle-tier server first, then the daemon and finally the FX desktop client:
cd ..
jlink/server/target/jlink/bin/server.sh &
jlink/daemon/target/jlink/bin/daemon.sh &
jlink/client/target/jlink/bin/client.sh
gonzo and password gonzo.
What is actually running now is a small multi-tier cascade:
- The server connects to PostgreSQL via JDBC and offers two
TRIP services:
the application service at
trip://localhost:8888/MyAppServerand the update service attrip://localhost:8890/MyAppUpdate. - The client and the daemon hold no database connection at all: they open
remote sessions to the server's TRIP URL. The same code would run unchanged if
they connected to the database directly — swap the
urlin the module'sbackend.propertiesand nothing else changes (that is the point of location transparency). - Each image reads its connection settings from a
backend.propertiesinside the image; passwords in it are stored encrypted (see Cryptor and EncryptedProperties).
The daemon logs events like login/logout in jlink/daemon/target/jlink/logs/daemon.log —
it listens for new Message PDOs and demonstrates a headless
ConsoleApplication.
Take a look at the other logs in jlink/server/target/jlink/logs and
jlink/client/target/jlink/logs.
Notice: on Windows, the scripts are named server.cmd, daemon.cmd and client.cmd.
Explore the code with your favorite IDE¶
You can use any Java IDE that supports at least Java 25, JPMS (Jigsaw) and Maven. There are no special plugins necessary. However, not all IDEs provide support for custom code folding regions, which are pretty nice to automatically collapse the wurblet-generated code woven into the sources. IntelliJ and Netbeans work fine out of the box. Others may need some extra plugins or configuration.
A good place to start reading is the User interface in myapp-pdo: the
model definition
lives in its comment blocks, and the
MyApp Walkthrough
follows it through all tiers, from the database row to the editor window.
Grow the Project¶
You rarely write a new entity by hand. The generated project pre-configures the
wizard plugin,
which interactively scaffolds new PDOs and operations consistent with the
example code — including class-id ranges and package conventions for the
masterdata and transactiondata profiles:
mvn tentackle-wizard:pdo # create a new entity
mvn tentackle-wizard:operation # create a new operation
After the wizard has generated the sources, rebuild: the wurblets fill in the persistence code and the SQL plugin produces the DDL (or a migration script for existing databases).
Further Reading¶
- Tentackle Project Archetype — what the archetype scaffolds and how each generated module fits together.
- MyApp Walkthrough — a guided tour through the generated application's code, tier by tier.
- Application Bootstrap — from
main()to a running tier. - Table of Contents — the full documentation map.
- Index — look up a concept and jump straight to the document that covers it.
- Tentackle Website — releases, API docs and background articles.