JMS Application Container Swiftlet
Overview
The JMS Application Container Swiftlet (sys$jac) provides a managed environment for running custom Java applications within the SwiftMQ router. It supports both statically configured applications and dynamic hot deployment via bundles, offering lifecycle management, classpath isolation, and optional scheduling for application execution.
Features
Static JMS Application Containers
Static JMS Application Containers are defined directly in the router's configuration and represent Java applications that are started and managed by the Swiftlet. Each static container specifies the main class to invoke, optional arguments, classpath entries, system properties, and lifecycle settings. The application is started by invoking its static main method and can be stopped via an optional static shutdown method. Applications can be enabled or disabled at runtime, and a startup delay can be configured to defer their launch after the router starts. The container ensures classpath isolation for each application and applies configured system properties before startup. If the main-return-is-stop property is enabled, the application is automatically stopped when its main method returns.
Classpath Management
Each static container can define its own set of classpath entries, allowing applications to load specific libraries without interfering with other applications or the router itself. Changes to the classpath require the application to be disabled first, ensuring classloader consistency.
System Properties Injection
System properties can be defined for each application and are set in the JVM before the application is started. These properties are managed dynamically and can be added or removed while the application is not running.
Lifecycle and Threading
Applications can be started and stopped via the enabled property. The use-virtual-thread property determines whether the application runs on a virtual thread or a platform thread. The startup delay allows for staged application initialization.
Configuration Example:
<swiftlet name="sys$jac">
<static-containers>
<static-container name="myapp" enabled="true" main-class="com.example.MyApp" main-class-arguments="arg1 arg2" startup-delay="1000" main-return-is-stop="true" use-virtual-thread="false">
<system-properties>
<system-property name="ENV" value="production"/>
</system-properties>
<classpath>
<path-entry name="lib1" value="/opt/myapp/lib/myapp.jar"/>
</classpath>
</static-container>
</static-containers>
</swiftlet>
Hot Deployment of JMS Applications
The Swiftlet supports dynamic deployment of JMS applications through hot deploy bundles. These bundles contain a deployment descriptor specifying the main class, shutdown method, arguments, system properties, and optional scheduling information. Upon deployment, the Swiftlet creates an isolated classloader, applies system properties, and manages the application lifecycle. Hot deployed applications can be started immediately or according to a defined schedule. The Swiftlet tracks running hot deploy applications and ensures proper cleanup on undeploy or router shutdown.
Deployment Descriptor Parsing
Each bundle must provide a descriptor XML specifying the required main class, shutdown method, and optional arguments, startup delay, system properties, and schedule. The Swiftlet validates and parses this descriptor during deployment.
Scheduling Support
If a schedule is defined in the deployment descriptor, the application is started and stopped according to the schedule using the router's scheduler. Schedule attributes include time expressions, calendar, date range, maximum runtime, and logging options.
Job Scheduling Integration
The Swiftlet integrates with the router's scheduler to allow both static and hot deployed applications to be started and stopped according to defined schedules. For static containers, a job factory is registered that can invoke the application by name. For hot deploys, each application with a schedule is registered as a temporary job with its own schedule parameters. This enables automated, time-based control of application lifecycles.
Job Factories and Job Groups
The Swiftlet registers job factories for static and hot deployed applications under the JAC job group. These factories create job instances that manage application start and stop operations, and handle job termination events if the application's main method returns.
Configuration Guide
Defining a Static JMS Application with Custom Classpath and System Properties
Use this scenario to configure a Java application that should be started automatically with specific system properties and additional libraries.
- Add a new
static-containerentry under thestatic-containerslist. - Specify the
main-classand setenabledto true. - Add required system properties and classpath entries.
- Optionally configure
main-class-arguments,startup-delay, anduse-virtual-thread.
<swiftlet name="sys$jac">
<static-containers>
<static-container name="analytics" enabled="true" main-class="com.company.AnalyticsMain" startup-delay="5000">
<system-properties>
<system-property name="LOG_LEVEL" value="DEBUG"/>
</system-properties>
<classpath>
<path-entry name="analytics-lib" value="/opt/analytics/analytics.jar"/>
<path-entry name="dep-lib" value="/opt/analytics/dep.jar"/>
</classpath>
</static-container>
</static-containers>
</swiftlet>
Hot Deploying an Application with a Schedule
Use this scenario to deploy a Java application as a bundle and have it started and stopped automatically according to a schedule.
- Prepare a bundle with the application JARs and a deployment descriptor XML specifying main class, shutdown method, and schedule.
- Deploy the bundle to the
jms-appdeploy space. - The application will be started and stopped according to the schedule defined in the descriptor.
Scheduler Jobs
Application Invoker
Description: Invokes a static Application
Hot Deploy Containers
Hot Deploy Containers enable automatic deployment of JMS applications without stopping the router.
The Deployment Bundle
A deployment bundle is a directory containing:
config.xml— the deployment descriptor- One or more
.jarfiles with the application classes - Optional native libraries (if JNI is used)
Deployment Descriptor
The descriptor (config.xml) defines how the application is started and stopped:
<deployment-descriptor>
<main-class>com.example.MyApp</main-class>
<main-class-arguments>
smqp://intravm/timeout=10000 IVMTopicConnectionFactory testtopic
</main-class-arguments>
<shutdown-method-name>stop</shutdown-method-name>
<main-return-is-stop>true</main-return-is-stop>
<startup-delay>2000</startup-delay>
<system-properties>
<system-property name="someprop" value="someval"/>
</system-properties>
</deployment-descriptor>
| Element | Required | Description |
|---|---|---|
main-class |
Yes | Fully qualified class name with a public static void main(String[]) method |
main-class-arguments |
No | Arguments to main, delimited by spaces |
shutdown-method-name |
Yes | Name of a public static void method in the main class that stops the application |
main-return-is-stop |
No | If true, returning from main marks the application as stopped |
startup-delay |
No | Milliseconds to delay startup after deployment |
system-properties |
No | System properties set before the application starts |
schedule |
No | Scheduler integration (see below) |
Scheduled Applications
Add a schedule element to run the application on a schedule managed by the Scheduler Swiftlet:
<deployment-descriptor>
<main-class>com.example.MyApp</main-class>
<shutdown-method-name>stop</shutdown-method-name>
<main-return-is-stop>true</main-return-is-stop>
<schedule time-expression="start 10:00 stop 17:00 delay 10m"
date-to="2025-12-31"
logging-enabled="true"/>
</deployment-descriptor>
Schedule attributes: time-expression (mandatory), calendar, date-from, date-to, max-runtime, logging-enabled.
Application Skeleton
A hot deploy application must not return from main until shutdown is called:
public class MyApp {
static final Object lock = new Object();
static boolean shutdownCalled = false;
public static void main(String[] args) {
// Start your JMS application here
// Wait until shutdown is called
synchronized (lock) {
while (!shutdownCalled) {
try { lock.wait(); } catch (InterruptedException ignored) {}
}
}
// Close all resources
}
public static void stop() {
synchronized (lock) {
shutdownCalled = true;
lock.notify();
}
}
}
Deploy Space Configuration
The deploy space for hot deploy bundles is configured in the Deploy Swiftlet:
<swiftlet name="sys$deploy">
<deploy-spaces>
<deploy-space name="jms-app" path="../data/jmsapp"/>
</deploy-spaces>
</swiftlet>
Deploy / Undeploy / Redeploy
Deploy: Create a bundle directory (e.g., data/jmsapp/myapp/), place config.xml and jar files in it. The application deploys within the next check-interval (default: 1 minute).
Undeploy: Remove config.xml and jar files from the bundle directory. The application undeploys within the next check-interval.
Redeploy: Update config.xml or any jar files. The application redeploys automatically within the next check-interval.
Each hot deployed application uses its own classloader, isolated from other applications and the router core. Deployment errors are reported to the router's error log and cause an automatic undeploy.
Configuration Reference
The top-level entity in routerconfig.xml is <swiftlet name="sys$jac">.
<static-containers> in <swiftlet name="sys$jac">
Static Containers
Each <static-container> entry is identified by its name attribute (the Static Container).
| Parameter | Type | Default | Mandatory | Reboot Required | Description |
|---|---|---|---|---|---|
startup-delay |
Long | 0 |
No | No | Delay (ms) to wait before start |
enabled |
Boolean | false |
No | No | Enables/Disables this Container |
main-class |
String | — | Yes | No | The class name with the main method |
main-class-arguments |
String | — | No | No | The Arguments of the Main Class (blank is Delimiter) |
main-return-is-stop |
Boolean | false |
No | No | Is the return from the main method is equal to stop? |
shutdown-method-name |
String | — | No | No | Optional static Shutdown Method Name |
use-virtual-thread |
Boolean | true |
No | No | Uses a virtual thread to run this app, otherwise a platform thread |
<swiftlet name="sys$jac">
<static-containers>
<static-container name="..." main-class="..."/>
</static-containers>
</swiftlet>
<system-properties> in <static-containers>
System Properties
Each <system-property> entry is identified by its name attribute (the System Property).
| Parameter | Type | Default | Mandatory | Reboot Required | Description |
|---|---|---|---|---|---|
value |
String | — | Yes | No | Property Value |
<swiftlet name="sys$jac">
<static-containers>
<static-container name="...">
<system-properties>
<system-property name="..." value="..."/>
</system-properties>
</static-container>
</static-containers>
</swiftlet>
<classpath> in <static-containers>
Classpath
Each <path-entry> entry is identified by its name attribute (the Path Entry).
| Parameter | Type | Default | Mandatory | Reboot Required | Description |
|---|---|---|---|---|---|
value |
String | — | Yes | No | Path Entry |
<swiftlet name="sys$jac">
<static-containers>
<static-container name="...">
<classpath>
<path-entry name="..." value="..."/>
</classpath>
</static-container>
</static-containers>
</swiftlet>
Changelog
13.1.2 (2025-04-15)
- Modified JACSwiftlet
- Modified configuration; Modified Descriptor