Setup
Set up the tutorial repository, install the required toolchain, and verify that you can build and run a lesson locally.
What you will do
In this section you will:
- clone the tutorial repository
- install Java and Gradle, preferably with SDKMAN
- run a few smoke tests against one tutorial module
- understand the difference between
run,installApp, and distribution tasks
Requirements
This tutorial is structured around a central Git repository, available at jpos/tutorial.
Each lesson now lives inside its own directory under tutorials/{lesson} instead of a dedicated Git branch.
The only tools you strictly need are:
- Git
- SdkMan
Even those are optional. You can download the repository archive directly, use a tool such as degit, or install Java and Gradle manually. SDKMAN is simply the easiest path for following along.
Clone the repository
git clone https://github.com/jpos/tutorial.git
Your checked out branch should now be main.
Replace {lesson} in commands such as ./gradlew :tutorials/{lesson}:installApp with the module you want to run (e.g., qbean-primer, qbean-support, qserver).
Install the toolchain
jPOS development requires Java and Gradle.
This tutorial uses SDKMAN to manage those versions. You can install them by other means if you prefer, but the commands below assume SDKMAN.
We will also show Maven-based application development later. For the tutorial itself, please stick to Gradle. It keeps the examples consistent and makes troubleshooting easier.
Run:
sdk env
This reads the required Java and Gradle versions from .sdkmanrc, which looks like this:
java=23.0.x
gradle=8.xx
If the given version of Java or Gradle is not installed, the sdk env command will tell you how to run sdk install in order to get them.
After sdk env, verify the toolchain:
java -version
gradle --version
You should see output like this:
openjdk version "23" 2024-09-17
...
...
------------------------------------------------------------
Gradle 8.10.1
------------------------------------------------------------
...
...
If setup goes wrong
The setup phase is usually straightforward, and most issues at this point are standard Java, Gradle, or SDKMAN problems. Once you get deeper into jPOS-specific behavior, the project and tutorials can move quickly enough that the documentation occasionally needs correction. If something feels inaccurate or unclear, ask.
See the resources page for the mailing list, chat channels, and support contact details.
Smoke Tests
Before we explain every moving part, verify that one lesson can build and run.
Check Gradle Tasks
Run:
./gradlew :tutorials/{lesson}:tasks
You should see a JPOS tasks section like this:
JPOS tasks
----------
dist - Generates jPOS distribution (Tar).
distnc - Generates jPOS distribution without configuration (Tar).
installApp - Installs jPOS based application.
run - Runs a jPOS based application.
viewTests - Open a browser with the tests results
zip - Generates jPOS distribution (Zip).
zipnc - Generates jPOS distribution without configuration (Zip).
Run from Gradle
Run:
./gradlew :tutorials/{lesson}:run
That should produce output similar to:
<log realm="Q2.system" at="2023-11-10T17:34:08.543173">
<info>
Q2 started, deployDir=/home/jpos/tutorial/tutorials/{lesson}/build/install/{lesson}/deploy, environment=default
</info>
</log>
...
...
Running directly from Gradle is mostly a quick verification step. In day-to-day work, you will usually use installApp for local iteration or build dist / distnc artifacts for deployment.
Stop the process with Ctrl-C.
Build distribution
Run:
./gradlew :tutorials/{lesson}:dist
This creates a full distribution under build/distributions. The filename will look like:
tutorials/{lesson}/build/distributions/{lesson}-0.0.1-SNAPSHOT.tar.gz
Its contents look like this:
$ tar ztvf tutorials/{lesson}/build/distributions/{lesson}-0.0.1-SNAPSHOT.tar.gz
drwxr-xr-x 0 0 0 0 Nov 10 17:46 {lesson}-0.0.1-SNAPSHOT/
drwxr-xr-x 0 0 0 0 Nov 10 15:45 {lesson}-0.0.1-SNAPSHOT/bin/
-rwxr-xr-x 0 0 0 80 Nov 10 15:44 {lesson}-0.0.1-SNAPSHOT/bin/start
-rwxr-xr-x 0 0 0 204 Nov 10 15:44 {lesson}-0.0.1-SNAPSHOT/bin/stop
-rwxr-xr-x 0 0 0 376 Nov 10 15:44 {lesson}-0.0.1-SNAPSHOT/bin/q2
drwxr-xr-x 0 0 0 0 Nov 10 15:52 {lesson}-0.0.1-SNAPSHOT/deploy/
-rw-r--r-- 0 0 0 484 Nov 10 15:52 {lesson}-0.0.1-SNAPSHOT/deploy/00_logger.xml
-rw-r--r-- 0 0 0 204 Nov 10 15:47 {lesson}-0.0.1-SNAPSHOT/deploy/99_sysmon.xml
drwxr-xr-x 0 0 0 0 Nov 10 15:45 {lesson}-0.0.1-SNAPSHOT/cfg/
-rw-r--r-- 0 0 0 0 Nov 10 15:45 {lesson}-0.0.1-SNAPSHOT/cfg/default.yml
drwxr-xr-x 0 0 0 0 Nov 10 16:48 {lesson}-0.0.1-SNAPSHOT/log/
-rw-r--r-- 0 0 0 0 Nov 10 16:48 {lesson}-0.0.1-SNAPSHOT/log/.gitkeep
-rw-r--r-- 0 0 0 956 Nov 10 17:30 {lesson}-0.0.1-SNAPSHOT/{lesson}-0.0.1-SNAPSHOT.jar
drwxr-xr-x 0 0 0 0 Nov 10 17:46 {lesson}-0.0.1-SNAPSHOT/lib/
-rw-r--r-- 0 0 0 1309179 Oct 31 09:41 {lesson}-0.0.1-SNAPSHOT/lib/jpos-3.0.2-SNAPSHOT.jar
-rw-r--r-- 0 0 0 475256 Jun 6 2015 {lesson}-0.0.1-SNAPSHOT/lib/org.osgi.core-6.0.0.jar
-rw-r--r-- 0 0 0 331605 Oct 31 09:41 {lesson}-0.0.1-SNAPSHOT/lib/snakeyaml-1.30.jar
-rw-r--r-- 0 0 0 87144 Feb 28 2014 {lesson}-0.0.1-SNAPSHOT/lib/jdbm-1.0.jar
-rw-r--r-- 0 0 0 3518946 Mar 7 2019 {lesson}-0.0.1-SNAPSHOT/lib/je-18.3.12.jar
-rw-r--r-- 0 0 0 327806 Dec 8 2021 {lesson}-0.0.1-SNAPSHOT/lib/jdom2-2.0.6.1.jar
-rw-r--r-- 0 0 0 65507 Feb 28 2014 {lesson}-0.0.1-SNAPSHOT/lib/javatuples-1.2.jar
-rw-r--r-- 0 0 0 994664 Oct 31 09:41 {lesson}-0.0.1-SNAPSHOT/lib/jline-3.21.0.jar
-rw-r--r-- 0 0 0 389033 Apr 6 2017 {lesson}-0.0.1-SNAPSHOT/lib/bsh-2.0b6.jar
-rw-r--r-- 0 0 0 53820 Jan 7 2019 {lesson}-0.0.1-SNAPSHOT/lib/commons-cli-1.4.jar
-rw-r--r-- 0 0 0 4550214 Oct 31 09:41 {lesson}-0.0.1-SNAPSHOT/lib/bcprov-jdk15to18-1.71.jar
-rw-r--r-- 0 0 0 336712 Oct 31 09:41 {lesson}-0.0.1-SNAPSHOT/lib/bcpg-jdk14-1.71.jar
-rw-r--r-- 0 0 0 41125 Jul 21 2022 {lesson}-0.0.1-SNAPSHOT/lib/slf4j-api-1.7.36.jar
-rw-r--r-- 0 0 0 173763 Mar 15 2020 {lesson}-0.0.1-SNAPSHOT/lib/HdrHistogram-2.1.12.jar
-rw-r--r-- 0 0 0 4018779 Oct 31 09:41 {lesson}-0.0.1-SNAPSHOT/lib/bcprov-jdk14-1.71.jar
What these tasks are for
To deploy jPOS in a target environment such as /opt/local/jpos:
- transfer the tarball file there.
- unpack it with the command
tar zxvf {lesson}-0.0.1-SNAPSHOT.tar.gz. - Navigate to the extracted directory using
cd /opt/local/jpos/tutorial-0.0.1, and launch jPOS by runningbin/q2.
That is the usual deployment shape. For development, installApp is usually more convenient because it builds the distribution and extracts it into build/install/<projectname> automatically.
In Gradle, you can abbreviate task names to streamline your workflow, provided that your abbreviation is unambiguous. For example, within a lesson module you can run ./gradlew :tutorials/{lesson}:iA instead of the longer ./gradlew :tutorials/{lesson}:installApp. This feature is particularly useful for frequently used tasks, saving time and reducing keystrokes.
To build, install, and run in one shot:
./gradlew :tutorials/{lesson}:installApp && ./tutorials/{lesson}/build/install/{lesson}/bin/q2
Each tutorial module ships with its own bin/q2 helper under tutorials/{lesson}/bin/q2; it shortens the previous command a little bit and looks like this:
#!/bin/sh
exec build/install/${PWD##*/}/bin/q2 "$@"
This simply delegates to the generated build/install/<projectname>/bin/q2. Here ${PWD##*/} expands to the current working directory, which usually matches the project name.
With that helper, local development becomes:
./gradlew :tutorials/{lesson}:iA && ./tutorials/{lesson}/bin/q2
If you want an even shorter workflow, you can alias g='./gradlew :tutorials/{lesson}' and place tutorials/{lesson}/bin/q2 somewhere on your $PATH, so you can run g iA && q2.
While the previous diagram is not technically correct (installApp doesn't create a tar.gz distribution, it does it on the fly), in practice, that's basically what happens when you call it.
Run Q2
You can now run ./tutorials/{lesson}/bin/q2 to start Q2 in the foreground.
Use Ctrl-C to stop it. You can also run bin/q2 --help to inspect the startup options; those are covered in later sections.
usage: Q2
-C,--config <arg> Configuration bundle
-c,--command <arg> Command to execute
-d,--deploydir <arg> Deployment directory
-e,--encrypt <arg> Encrypt configuration bundle
-E,--environment <arg> Environment name.
Can be given multiple times (applied in
order, and values may override previous
ones)
-Ed,--envdir <arg> Environment file directory, defaults to
cfg
-h,--help Usage information
-i,--cli Command Line Interface
-n,--name <arg> Optional name (defaults to 'Q2')
-Nd,--no-dynamic Disables dynamic classloader
-Ns,--no-scan Disables deploy directory scan
-p,--pid-file <arg> Store project's pid
-r,--recursive Deploy subdirectories recursively
-s,--ssh Enable SSH server
-sa,--ssh-authorized-keys <arg> Path to authorized key file (defaults
to 'cfg/authorized_keys')
-sh,--ssh-host-key-file <arg> SSH host key file, defaults to
'cfg/hostkeys.ser'
-sp,--ssh-port <arg> SSH port (defaults to 2222)
-su,--ssh-user <arg> SSH user (defaults to 'admin')
-v,--version Q2's version
If for example you call bin/q2 --cli you'll get into jPOS' command line interface. Pressing tab will show you the available commands:
q2>
calcluhn echo license shownr sysmon version
clr env logger_benchmark shutdown tail whoami
date exit man sleep tmmon
deploy help mem smconsole tzcheck
dumpmetrics install obf ssm uptime
you can play with some commands, like env, version, shownr (show NameRegistrar), or enter a "subsystem" that are basically a group of commands that can share context. One example is the ssm (software security module). When you call it, the prompt changes from q2> to ssm> and if you press the tab key, you can see the available subcommands, e,g,:
ck cvv fk gc ik init ke
jPOS includes a small set of CLI (Command Line Interface) commands, offering both practical utilities and demonstrative examples. Key utilities like ssm (Software Security Module CLI) are highly functional, while others such as sysmon (SystemMonitor) and shownr (show NameRegistrar) serve as illustrative examples. The core takeaway is the extensibility of jPOS: the org.jpos.q2.cli package hosts a fully pluggable framework. This framework empowers you to craft custom CLI commands, seamlessly integrating with jPOS's comprehensive suite of components, thus enhancing the versatility and functionality of your jPOS applications.
Typical jPOS applications often interface with databases, HSMs, key vaults, and remote hosts. For specific tasks like system setup, database updates and migrations, or cryptography debugging, access to a secure, functioning system is crucial. Using standalone command line scripts for these tasks can pose security risks if they're written separately, as they need access to sensitive configurations. However, developing a CLI command within jPOS ensures that it benefits from the system's existing security posture. This approach significantly reduces the likelihood of security breaches, maintaining the integrity of your system while performing necessary operations.
Many jPOS-EE modules have their set of CLI commands and subsystems, for example, the flyway integration module has a very handy flyway command that you can use to inspect the status of the database, run a migration, etc.
You may have observed the --ssh option. This feature enables you to use SSH to connect to an active Q2 instance and access a CLI prompt for executing commands. This functionality is particularly beneficial for integrating with your administrative processes and tools like Ansible, Rundeck, and others.