Skip to main content
Skip table of contents

JMS Application Container Swiftlet

The JMS Application Container Swiftlet provides containers to run JMS applications as a component within the virtual machine of a SwiftMQ router.

These kinds of JMS applications are not different from any other JMS application. They do not have to implement any SwiftMQ interfaces nor do they have to have any special kind of code structure. The only exceptions are an optional method to stop the application by the router and to avoid System.exit() calls. If a shutdown method is defined, this method is discovered by Java reflection. So there is no proprietary code and therefore no vendor lock-in involved.

A JMS application running within a container typically uses JNDI with a JNDI provider URL

JAVA
    smqp://intravm/timeout=1000

which connects to the router via an intra-VM JMS connection. Once a JNDI InitialContext is created, it obtains an intra-VM connection factory from JNDI:

JAVA
    TopicConnectionFactory tcf = (TopicConnectionFactory)ctx.lookup("IVMTopicConnectionFactory");

All connections created from this connection factory connect to the router also via an intra-VM connection.

How a JMS Application is started

The start of a JMS application takes place by calling its main method. The arguments to the main method can be configured. The main method may block, e.g. due to a loop, or it may return immediately, e.g. if only a message listener has been registered. An attribute main-return-is-stop can be specified which states whether a return from the main method should mark the application as stopped. The default is false. In that case, the only way to stop is to call the shutdown method.

How a JMS Application is stopped

A running JMS application is automatically stopped during the router's shutdown sequence. To stop it manually, a shutdown method has to be defined:

Example:

JAVA
      public static void stopMyApp()
      {
        try
        {
          connection.close();
        } catch (JMSException e)
        {
        }
      }

The method has to be public static with a return type void. The method name can be configured and is discovered by Java reflection. Within the shutdown method, all resources should be closed and all threads started from the JMS application, should terminate.

If the application stops by returning from its main method, the container's attribute main-return-is-stop must be set to true.

Avoid System.exit!

A JMS application runs inside the virtual machine of the router, therefore you should avoid to call System.exit(). For example, instead of this kind of error handling within the main method:

JAVA
      public static void main(String[] args)
      {
        if (args.length < 4)
        {
          System.err.println("<smqp-url> <tcf> <topic> <nmsgs>");
          System.exit(-1);
        }
        ...
      }

you should use this:

JAVA
      public static void main(String[] args)
      {
        if (args.length < 4)
        {
          System.err.println("<smqp-url> <tcf> <topic> <nmsgs>");
          return;
        }
        ...
      }

How a JMS Application is deployed

The JMS Application Container Swiftlet provides 2 different container types: Static containers and hot deploy containers.

A static container is configurable via SwiftMQ Explorer/CLI and the router's configuration file. It contains definitions of the class name, classpath, system properties, shutdown method, etc. If a shutdown method is defined, the JMS application can be started and stopped by CLI. If not, the application is typically started during the router's startup and stopped during its shutdown.

A hot deploy container listens on a deploy space of the Deploy Swiftlet. Deploying a JMS application takes place by copying a deployment descriptor and at least 1 jar file into the deployed space. The JMS application is automatically started during deployment and stopped during undeployment. A shutdown method is mandatory for hot deployable JMS applications. The deployment descriptor contains the definitions of the JMS application (class name, system properties, etc). Hot deployment enables you to upgrade a JMS application automatically without stopping the router, e.g. deploying a new version of a JMS application with totally different classes into a production system during runtime.

Static Containers

A static JMS application container enables you to run any application (it doesn't have to be a JMS application; you can also start your favorite servlet engine) by configuring the resp. container definitions via the router's configuration file or via SwiftMQ Explorer/CLI. Once it is configured, it can be enabled which means it is started. An enabled JMS application can only be disabled if it provides a custom shutdown method. This method must be public static with a void return type. The name of the method is configurable since it is discovered by Java reflection.

Configuration

The configuration of a static JMS application consists of

  • Name of the class with the main method.

  • Optional arguments to the main method, delimited by blanks.

  • Attribute main-return-is-stop to indicate the application is stopped when returning from main.

  • Optional name of the shutdown method.

  • A startup delay in milliseconds is useful to create a start order of applications.

  • A list of classpath entries.

  • A list of system properties to set.

  • An enabled attribute.

The following example shows the configuration of 2 static containers, a subscriber and a publisher, where the publisher is started 20 seconds after the subscriber:

XML
    <swiftlet name="sys$jac">
      <static-containers>
        <static-container name="01"
              main-class="TestSubscriber"
              main-class-arguments="1 smqp://intravm/timeout=10000 IVMTopicConnectionFactory testtopic 1"
              main-return-is-stop="true"
              enabled="true">
          <classpath>
            <path-entry name="01" value="d:/testdriver"/>
          </classpath>
          <system-properties>
            <system-property name="test" value="test"/>
          </system-properties>
        </static-container>
        <static-container name="02"
                main-class="TestPublisher"
                main-class-arguments="smqp://intravm/timeout=10000 IVMTopicConnectionFactory testtopic 1"
                shutdown-method-name="stop"
                startup-delay="2000"
                enabled="true">
          <classpath>
            <path-entry name="01" value="d:/testdriver"/>
          </classpath>
          <system-properties/>
        </static-container>
      </static-containers>
    </swiftlet>

Note that the containers are started in order of the name attribute of the static-container element. However, since they run asynchronously in different threads, the startup-delay ensures that the publisher starts after the subscriber is already running.

The publisher has a shutdown-method-name defined. The name of the method is stop. Thus, the class TestPublisher has to have this method:

Example:

JAVA
    public static void stop()
    {
      // do whatever to stop this app!
      try
      {
        connection.close();
      } catch (JMSException e)
      {
      }
    }

The shutdown method enables you to enable/disable (start/stop) the TestPublisher at any time via SwiftMQ Explorer/CLI, so you can easily restart this application. You cannot do this with the TestSubscriber, because it doesn't have a shutdown method. However, since it has the attribute main-return-is-stop set to true, the container is disabled after TestSubscriber returns from its main method. Thereafter it can be started again.

Start/Stop a static Application Container

A static JMS application is started by enabling its container via the enabled attribute. This leads to a call to the main method of the program in a different thread from the thread pool jac.runner.

The call to the main method may return immediately or it may block until the program has finished. It is possible to specify if the return from the main method should mark the container as disabled. This can be done via the attribute main-return-is-stop. The default value is false.

Therefore, a JMS application within the main method or with a returned main method but with attribute main-return-is-stop set to false is still enabled, thus running. Such an application can only be stopped by invoking the shutdown method.

A JMS application without a shutdown method cannot be stopped, except via the return from the main method which has to be specified via the attribute main-return-is-stop.

A shutdown method should always be able to asynchronously close and clean up all resources (e.g. connections, threads, etc) without blocking.

ClassLoaders

Each configured static container uses its own dedicated classloader. The parent class loader is the one that loaded the SwiftletManager class, hence, all SwiftMQ jar files are already present in the classpath and you don't have to define it again.

Since a dedicated classloader is used for each container, it is possible to run the same application in different instances, even if the static main or a shutdown method will be called. These methods are called on physically different classes, thus all static references within these classes (such as a static connection object) are contained in each container but they are different; a connection.close() will therefore only close it in one instance but not in the other.

If you delete the configuration of a static container, the classes are physically removed. If you change the application and create a new configuration, the new classes are loaded and you will have the same effect as with hot deployment.

Example

This example shows how to create and use a static container via the SwiftMQ Explorer. We use PubSubPublisher from the SwiftMQ samples.

In the SwiftMQ Explorer App, click on JMS Application Container Swiftlet / Static Containers:

Click Create a new Entity and fill the fields. Don't enable it, because you don't have a correct classpath yet.

Select the Classpath node:

Create a new path entry. The name specifies the order of the classpath entries. You can create as many entries as you want. The value is the actual path entry. It can be everything you normally specify in classpaths (jars, zips, directories).

If your application needs system properties to be set, click on the System Properties node:

Specify the system property. You can create as many entries as you want. Keep in mind that these system properties are visible for all applications since they run within the same virtual machine.

Well, that's it. Now you have configured your application.

To start it, toggle the Enabled attribute. The application will now be started with a delay of 2 seconds. You can see a new entry in the Usage section:

To stop it, toggle the Enabled attribute.

Hot Deploy Containers

JMS applications can be hot deployed. In contrast to static JMS application containers, hot deploy JMS application containers are not configurable via CLI or the router's configuration file. Rather, they are configured via their deployment descriptor which is part of the deployment bundle.

Hot deployment enables you to upgrade a JMS application automatically without stopping the router, e.g. deploying a new version of a JMS application with totally different classes into a production system during runtime.

A deployment descriptor can optionally contain a schedule to run the application as a job from the Scheduler Swiftlet, thus, enabling you to run any Java application as a hot deployable job.

The Deployment Bundle

The collection of all necessary files to hot deploy a JMS application is called a deployment bundle. It consists of:

  • The deployment descriptor,

  • all necessary jar files,

  • all necessary native libraries (in case JNI is used).

The Deployment Descriptor

The deployment descriptor is a small XML file with the name config.xml. It contains similar configuration information as for static JMS application containers:

  • Name of the class with the main method.

  • Optional arguments to the main method, delimited by blanks.

  • Mandatory name of the shutdown method.

  • An optional startup delay in milliseconds, useful to create a start order of applications.

  • A list of system properties to set.

  • Optional schedule to schedule the application as a job.

A shutdown method is mandatory for hot deploy JMS applications because it must be stopped during an undeployment. A classpath isn't specified, because the classpath consists of the jar files etc contained in the bundle. Further, a hot deploy JMS application will be automatically started during deployment and stopped before it is undeployed.

The following example deployment descriptor contains the configuration of the TestPublisher example:

XML
      <deployment-descriptor>
        <main-class>TestPublisher</main-class>
        <main-class-arguments>
          smqp://intravm/timeout=10000 IVMTopicConnectionFactory testtopic 1000000
        </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>
main-class

Contains the fully qualified class name of the class with the main method.

main-class-arguments

This is optional. Contains the arguments to the main class, delimited by blanks.

shutdown-method-name

Contains the name of the shutdown method. It has to be public static with a return type of void and has to be part of the main class. The shutdown method must close all resources of the JMS application and must stop all threads started from the application.

Example:

JAVA
        public static void stop()
        {
          // do whatever to stop this app!
          try
          {
            connection.close();
          } catch (JMSException e)
          {
          }
        }
main-return-is-stop

This is optional. Specifies whether a return from the main method marks the application as stopped.

startup-delay

Contains a millisecond value that is used to delay the start of the application after it has been deployed. This is useful to create a start sequence of hot deploy JMS applications because when the router starts, all hot deployed JMS applications are started asynchronously in different threads.

system-properties

This is optional. Contains system-property elements to define necessary system properties for the application. These system properties are visible to all JMS applications because they use the same virtual machine.

schedule

A deployment descriptor can contain an optional schedule element. If specified, the application will be invoked on the schedule from the Scheduler Swiftlet. The management of job registration etc. at the Scheduler Swiftlet takes place automatically. A schedule element can contain the following attributes:

  • time-expression: A at or repeat expression. Mandatory.

  • calendar: Name of the calendar to use. Optional.

  • date-from: A start date (dd-MM-yyyy). Optional. Default: now.

  • date-to: A end date (dd-MM-yyyy). Optional. Default: fowever.

  • max-runtime: A maximum runtime. Optional. If not specified, the attribute main-return-is-stop must be set to true.

  • logging-enabled: Start/stop of a job instance if logged to SwiftMQ's log file. Optional. Default: false.

A schedule is created dynamically at the Scheduler Swiftlet during the deployment and deleted during the undeployment so the elements of the schedule are the same as you have to specify for schedules of the Scheduler Swiftlet. For further infos please take a look there.

The following shows an example of the above deployment descriptor for the TestPublisher. However, now it is scheduled as a job:

XML
        <deployment-descriptor>
          <main-class>TestPublisher</main-class>
          <main-class-arguments>
            smqp://intravm/timeout=10000 IVMTopicConnectionFactory testtopic 1000000
          </main-class-arguments>
          <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="2003-11-20"
              logging-enabled="true"/>
          <system-properties>
            <system-property name="someprop" value="someval"/>
          </system-properties>
        </deployment-descriptor>

The Deployment Classes

There has to be at least 1 jar file in the bundle, containing the necessary classes of the application. Of course, it can be more than 1 jar file, however, it is not possible to use plain .classes. You have to jar it. You also cannot use .zip files. If your application needs native libraries, they have to be part of the bundle.

A dedicated class loader is created during deployment, referencing all jar files and native libraries in the bundle. The parent class loader is the one that loaded the SwiftletManager class, hence, all SwiftMQ jar files are already present in the classpath.

Skeleton of a Hot Deploy JMS Application

This is a skeleton of a hot deploy JMS application:

JAVA
    public class JacSkeleton
    {
      static final Object obj = new Object();
      static final boolean shutdownCalled = false;

      public static void main(String[] args)
      {
        // Start your JMS application here

        // Then wait here until shutdown is called
        try
        {
          synchronized (obj)
          {
            if (!shutdownCalled)
             obj.wait();
          }
        } catch (InterruptedException ignored)
        {
        }

        // Now close all resources and terminate
      }

      public static void shutdown()
      {
        // Trigger main to stop
        synchronized (obj)
        {
          shutdownCalled = true;
          obj.notify();
        }
      }
    }

It ensures that the main method doesn't terminate until shutdown is being called.

How To Deploy

The JMS Application Container Swiftlet listens on a deploy space named jms-app, defined in the Deploy Swiftlet configuration:

XML
    <swiftlet name="sys$deploy">
      <deploy-spaces>
        <deploy-space name="extension-swiftlets" path="../data/deploy"/>
        <deploy-space name="jms-app" path="../data/jmsapp"/>
      </deploy-spaces>
    </swiftlet>

The path defined in the deploy space is the directory where you create your bundles.

Directory Structure

The directory data/jmsapp is the path of the deploy space jms-app. There is 1 JMS application deployed. The name is testpub. This directory is called the "bundle directory". Directly within this directory are stored the deployment descriptor (config.xml) and 1 jar file (test.jar). The sub-directory _deployed_... contains the actual deployment. It is created and managed by the Deploy Swiftlet. It contains copies of the deployment descriptor and the bundle jar files.

Creating a Bundle (Deploy)

Create a bundle directory, e.g. data/jmsapp/testpub. Copy the deployment descriptor config.xml and your jar files and/or native libs into this directory. Your application will be deployed within the next check-interval (default 1 minute).

Removing a Bundle (Undeploy)

Remove the deployment descriptor config.xml and your jar files / native libs out of the bundle directory. Don't touch the actual deployment (_deployed_... directories)! Your application will be undeployed within the next check-interval (default 1 minute).

Changing a Bundle (Redeploy)

Change either the deployment descriptor config.xml or change any of the jar files / native libs. Your application will be redeployed within the next check-interval (default 1 minute).

Errors during Deployment

Any error during deployment leads to an undeploy of the bundle. An attempt is made on every check-interval of the deploy space to deploy it again. So in case of an error within your application, you can simply overwrite your jar files with a new version. All errors during deployment are reported to the router's error log file.

Job Scheduling

The following sections describe how to schedule static and hot deploy applications.

How to schedule static Applications

The JMS Application Container registers jobs in job group JAC at the Scheduler Swiftlet:

These jobs can be scheduled via the Scheduler Swiftlet to run at specific times or in intervals, based on calendars and so on.

Application Invoker

The Application Invoker job invokes a static JMS application whose name must be specified as a job parameter. It requires that the static JMS application has a shutdown method defined, otherwise the job cannot stop it. Either the JMS application must have the attribute main-return-is-stop set to true or a maximum run time must be specified in the schedule, otherwise, the job runs forever.

The implementation of the Application Invoker job is quite simple. It sets the enabled attribute to true on job start and to false on job stop. Therefore, a static JMS application that should run as a job should be initially disabled.

Parameter

Mandatory

Description

Application Name

Yes

Name of the static JMS application.

How to schedule Hot Deploy Applications

To schedule a hot deploy application is quite easy: Just add a schedule element to the deployment descriptor:

XML
      <deployment-descriptor>
        <main-class>TestPublisher</main-class>
        <main-class-arguments>
          smqp://intravm/timeout=10000 IVMTopicConnectionFactory testtopic 1000000
        </main-class-arguments>
        <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="2003-11-20"
            logging-enabled="true"/>
        <system-properties>
          <system-property name="someprop" value="someval"/>
        </system-properties>
      </deployment-descriptor>

A schedule is created dynamically at the Scheduler Swiftlet during the deployment and deleted during the undeployment so the elements of the schedule are the same as you have to specify for schedules of the Scheduler Swiftlet. For further info please take a look there.

Configuration

The configuration of the JMS Application Container Swiftlet is defined within the element

XML
      <swiftlet name="sys$jac" .../>

of the router's configuration file.

Element List "static-containers", Parent Element: "swiftlet"

Static Containers. This element list contains zero or more "static-container" elements with this template definition:

Definition

Attribute

Type

Mandatory

Description

name

java.lang.String

Yes

Name of this Static Container

startup-delay

java.lang.Long

No

Delay (ms) to wait before start

enabled

java.lang.Boolean

No

Enables/Disables this Container

main-class

java.lang.String

Yes

The class name with the 'main' method

main-class-arguments

java.lang.String

No

The Arguments of the Main Class (blank is Delimiter)

main-return-is-stop

java.lang.Boolean

No

Is the return from the 'main' method is equal to stop?

shutdown-method-name

java.lang.String

No

Optional static Shutdown Method Name

Values

Attribute

Values

startup-delay

Default: 0

enabled

Default: false

main-class

main-class-arguments

main-return-is-stop

Default: false

shutdown-method-name

Element List "system-properties", Parent Element: "static-container"

System Properties. This element list contains zero or more "system-property" elements with this template definition:

Definition

Attribute

Type

Mandatory

Description

name

java.lang.String

Yes

Name of this System Property

value

java.lang.String

Yes

Property Value

Values

Attribute

Values

value

Element List "classpath", Parent Element: "static-container"

Classpath. This element list contains zero or more "path-entry" elements with this template definition:

Definition

Attribute

Type

Mandatory

Description

name

java.lang.String

Yes

Name of this Path Entry

value

java.lang.String

Yes

Path Entry

Values

Attribute

Values

value

Element "usage", Parent Element: "swiftlet"

Running JMS Application Containers.

Element List "statics", Parent Element: "usage"

Running static JMS Application Containers. This element list contains zero or more "static" elements with this template definition:

Definition

Attribute

Type

Mandatory

Description

name

java.lang.String

Yes

Name of this Running static JMS Application Container

start-time

java.lang.String

No

Start Time

Values

Attribute

Values

start-time

Element List "hot-deploys", Parent Element: "usage"

Hot Deployed JMS Application Containers. This element list contains zero or more "hot-deploy" elements with this template definition:

Definition

Attribute

Type

Mandatory

Description

name

java.lang.String

Yes

Name of this Hot Deployed JMS Application Container

deploy-time

java.lang.String

No

Deploy Time

startup-delay

java.lang.Long

No

Delay (ms) to wait before start

main-class

java.lang.String

No

The class name with the 'main' method

main-class-arguments

java.lang.String

No

The Arguments of the Main Class (blank is Delimiter)

shutdown-method-name

java.lang.String

No

Mandatory static Shutdown Method Name

Values

Attribute

Values

deploy-time

startup-delay

Default: 0

main-class

main-class-arguments

shutdown-method-name

Element List "system-properties", Parent Element: "hot-deploy"

System Properties. This element list contains zero or more "system-property" elements with this template definition:

Definition

Attribute

Type

Mandatory

Description

name

java.lang.String

Yes

Name of this System Property

value

java.lang.String

Yes

Property Value

Values

Attribute

Values

value

Element "Job Schedule", Parent Element: "hot-deploy"

Job Schedule.

Definition

Attribute

Type

Mandatory

Description

logging-enabled

java.lang.Boolean

No

If true, start/stop are logged in SwiftMQ's log file

calendar

java.lang.String

No

Apply this Calendar

date-from

java.lang.String

No

From Date

date-to

java.lang.String

No

To Date

max-runtime

java.lang.String

No

n('s'|'m'|'h'), e.g. 30m

time-expression

java.lang.String

No

('at' HH:mm[:ss][, HH:mm[:ss]...]) | ('start' HH:mm[:ss] 'stop' HH:mm[:ss] 'delay' n('s'|'m'|'h' ['repeat' n])

Values

Attribute

Values

logging-enabled

Default: false

calendar

date-from

Default: now

date-to

Default: forever

max-runtime

time-expression

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.