Skip to main content

The jPOS CLI

Q2 ships with a built-in command-line interface that gives you interactive access to a running jPOS instance. Whether you want to inspect the NameRegistrar, manage deploy descriptors, run security module operations, or add your own operational tooling, the CLI is the natural entry point.

Starting the CLI

Pass the --cli flag to start Q2 with an interactive shell:

./bin/q2 --cli

The prompt changes to q2> and tab-completion is available for all discovered commands.

You can also run a sequence of commands non-interactively with -c, separating commands with ;:

./bin/q2 -c "uptime; shutdown --force"
Combining -c with --cli

You can combine both flags. Commands specified with -c run first; if --cli is also present, the interactive shell opens afterwards. This is useful for scripted pre-flight checks followed by a live session.

To close an interactive session, press Ctrl-C. To stop Q2 entirely from within the CLI, use shutdown --force.

The deploy-cli directory

When Q2 starts with --cli and no --deploy directory is explicitly specified, it uses deploy-cli instead of the default deploy directory.

This is intentional. A typical deploy directory contains channels, servers, MUXes, and a TransactionManager — the full transaction processing stack. When you just want a CLI session to inspect the system, query the NameRegistrar, or run key management operations, you don't need all that overhead. deploy-cli lets you configure a lightweight set of QBeans (perhaps just a logger and a service or two) without starting the whole application.

Scripted automation

This also makes Q2 a practical scripting target. Running:

./bin/q2 -c "uptime; shutdown --force"

starts with deploy-cli, executes the commands, and exits cleanly — suitable for CI pipelines, health checks, or any automated workflow.

How commands are discovered

The CLI uses a simple class-loader lookup. When you type a command, it is uppercased and looked up by class name under the registered package prefixes. The default prefix is org.jpos.q2.cli, so typing uptime causes Q2 to instantiate org.jpos.q2.cli.UPTIME.

Every CLI command implements a single interface:

public interface CLICommand {
void exec(CLIContext cli, String[] args) throws Exception;
}

The class name is the command name. To add a new command, create a class implementing CLICommand, place it in org.jpos.q2.cli (or any registered prefix), and it becomes available immediately — no registration, no XML, no restart required.

Writing a custom command

package org.jpos.q2.cli;

import org.jpos.q2.CLICommand;
import org.jpos.q2.CLIContext;

public class HELLO implements CLICommand {
@Override
public void exec(CLIContext cli, String[] args) throws Exception {
cli.println("Hello, " + (args.length > 1 ? args[1] : "world") + "!");
}
}

Put this class on the classpath and hello (or HELLO) becomes a valid CLI command.

Autocompletion for free

Because commands are discovered by class name, tab-completion at the q2> prompt automatically reflects whatever CLICommand implementations are on the classpath. No additional configuration is needed.

Man pages

The man command looks for a plain-text resource file named <COMMAND>.man in the same classpath package as the MAN class itself (org/jpos/q2/cli/):

org/jpos/q2/cli/UPTIME.man
org/jpos/q2/cli/SHOWNR.man
q2> man uptime

To ship a man page alongside your own command, place a <YOURCOMMAND>.man file in the same package on the classpath:

org/jpos/q2/cli/HELLO.man

The content is plain text and is printed verbatim to the terminal.

Subsystems

Some commands drop you into a sub-context — a nested prompt with its own scoped command set. These implement CLISubSystem:

public interface CLISubSystem {
String getPrompt(CLIContext ctx, String[] args);
String[] getCompletionPrefixes(CLIContext ctx, String[] args);
}

getPrompt() returns the prompt string shown while inside the subsystem. getCompletionPrefixes() returns the package prefixes scanned for commands within the subsystem — so tab-completion inside the subsystem is automatically scoped to its own command set.

Two built-in subsystems ship with jPOS:

  • deploy — manages deploy descriptors; scans org.jpos.q2.cli.deploy.
  • ssm — security module operations; scans org.jpos.q2.cli.ssm.actions.
q2> ssm
ssm> help
ssm> exit
q2>

Every subsystem gets exit for free. Typing exit inside a subsystem returns you to the parent q2> prompt. Note that exit at the top-level q2> prompt does nothing — use shutdown --force to stop Q2, or Ctrl-C to close the interactive session.

Tab-completion works inside subsystems exactly as it does at the top level, scoped to the subsystem's own package prefix.

Creating your own subsystem

package org.jpos.q2.cli;

import org.jpos.q2.CLIContext;
import org.jpos.q2.CLISubSystem;

public class MYTOOL implements CLISubSystem {

@Override
public String getPrompt(CLIContext ctx, String[] args) {
return "mytool> ";
}

@Override
public String[] getCompletionPrefixes(CLIContext ctx, String[] args) {
return new String[] { "com.mycompany.cli.mytool." };
}
}

Commands placed in com.mycompany.cli.mytool are then available inside the mytool> subsystem, with tab-completion and man-page support included.

Build your operational tooling here

The CLI is the right home for operational tools — key management, diagnostic queries, NameRegistrar inspection, transaction replay scripts. Every team ends up building ad-hoc utilities; the CLI gives those tools a first-class home with autocompletion, contextual help, and direct access to the running Q2 instance.