JMS Example Introduction

This project shows an example of integrating JMS and ActiveSpaces Transactions transactions.

Please see the enclosed source and javadoc for this example.

Overview

The JMS (Java Message Service) example demonstrates how ActiveSpaces Transactions integrates with JMS and extends message transactions with ActiveSpaces Transactions-based application-level transactions. The example is based on a "Funds Transfer" use case scenario, in which a Customer requests a Bank to transfer funds between two accounts. The transfer involves two separate account operations (debit and credit), with the overall integrity of account balances ensured by a ActiveSpaces Transactions transaction.

Note: The example code highlights the benefits of using ActiveSpaces Transactions for implementing highly reliable transactions in a financial domain. However, the example omits the many other aspects of implementing a real-life production system, such as the security aspects of financial transactions.

Functional Description

The example "Funds Transfer" use case scenario involves these two actors:

  • Customer
  • Bank

    Customer has two accounts (Source Account and Destination Account) held at Bank. Customer requests Bank to transfer funds from Source Account to Destination Account. The transfer is achieved by two separate financial operations carried out by Bank on the accounts:

  • a debit of the amount from Source Account, and
  • a credit of the same amount to Destination Account

Customer receives a 'receipt' of the funds transfer which contains the amount transferred and the new account balances. Bank allows a funds transfer only if the requested amount is available in the source account. In the use case scenario Customer makes repeated transfers of a fixed amount until there are insufficient funds available in Source Account, at which point the scenario completes.

Customer and Bank are distributed actors and the interactions between them are implemented via asynchronous messaging supported by a JMS provider. In order to accomplish a transfer, Customer sends two messages to Bank: a Debit message (to debit the Source Account) and a Credit message (to credit the Destination Account with the same amount). After Bank completes the debit/credit operations it sends a Receipt message to Customer.

The messages and their parameters are defined in the following list:

  • Debit message
    • debit amount (to be debited from source account)
  • Credit message
    • credit amount (to be credited to destination account)
    • Receipt message
      • boolean confirmation flag set to true if transfer succeeded
      • balance of Source Account at transfer transaction completion
      • balance of Destination Account at transfer transaction completion
      • retry flag set to true if transfer transaction had to be replayed (see below for explanation of fund transfer failure simulation)

Funds Transfer Failure Simulation

The example simulates a failure case in which random failures occur at Bank just after the debit from the Source Account is completed and before the credit to Destination Account is started. The ActiveSpaces Transactions transaction ensures the data integrity of the two accounts and a retry flag is returned in the Receipt messages (for informational purposes only).

Transaction Design

Customer and Bank are distributed actors that use the JMS point-to-point messaging for communications between themselves. The Bank actor uses JMS local transactions integrated with ActiveSpaces Transactions transactions (a ActiveSpaces Transactions transaction is run within the scope of a JMS transaction).

Customer Transactions

The Customer actor invokes two JMS local transactions:

Customer Send Transaction

Customer sends both Credit and Debit messages in a single JMS local transaction. The Customer uses a transactional session and the session's 'commit()' operation to commit the delivery of the two messages to the JMS provider in a single transaction.

Customer Receive Transaction

Customer receives a Receipt message in a separate JMS local transaction. It commits the consumption of the message by invoking the JMS session's commit operation.

Bank Transactions

The Bank actor receives the debit and credit messages in a JMS local transaction. When both messages are received, the Bank actor starts a ActiveSpaces Transactions transaction that encloses both the debit and credit operations on the accounts involved. Upon completing the ActiveSpaces Transactions transaction, Bank sends a Receipt message back to the Customer actor. The Bank actor then commits both the received messages and the delivery of the Receipt message to the JMS provider in a single JMS session's commit operation.

A failure randomly occurring between the credit and debit account operations is simulated by invoking a rollback within a ActiveSpaces Transactions transaction. In this case, the Bank actor does not send a Receipt message and calls the rollback operation on the JMS transactional session. This will cause the JMS to re-deliver the debit and credit messages to the Bank actor.

Deployment

ActiveSpaces Transactions Server

The example can be built and run directly using the ActiveSpaces Transactions development client, or using the ActiveSpaces Transactions plugin for Maven.

Both Customer and Bank actors are run as separate threads within a ActiveSpaces Transactions server.

JMS Provider

The example depends on and uses Apache ActiveMQ as the JMS provider implementation. The example instantiates and starts an embedded message broker for its purposes (i.e. the example application starts its own message broker within the JVM it is running in).

The example takes an optional command-line argument which can be used to specify the URL of the embedded broker's listener. The listener URL defaults to tcp://localhost:61616 if it is not specified on the command line.

The ActiveMQ jar file required by the example is included in the ActiveSpaces Transactions examples distribution. This file must be copied to the ActiveSpaces Transactions Server's Deploy Directory (see the Developer's Guide for details about the Deploy Directory). Otherwise, the embedded message broker may take several minutes to start and a time-out error may occur during the example's execution.

Using Example

Building and Running

This project uses the deploy:exec target to invoke the main class on a ActiveSpaces Transactions server. See the documentation for the TIBCO ActiveSpaces Transactions Deployment Maven plugin for more information on configuring the client connectivity.

The following invocation will run the example on the ActiveSpaces Transactions Development Appliance:

NOTE: kabira-server.local only works on OS X. Other platforms may use a different name, or have to specify an IP address.

mvn -Dcom.kabira.fluency.hostName=kabira-server.local
    -Dcom.kabira.fluency.administrationPort=2000 \
    -Dcom.kabira.fluency.domainNode=A \
    compile deploy:exec

Example Output

The Customer actor prints the following information to the standard output upon successful exit:

  • total amount of funds transferred
  • total number of transfer (debit/credit) transactions performed
  • number of transfer transactions retried due to failures

Dependencies

See the Dependencies page for information on the example's dependencies.

For each dependency listed in the Project Dependencies section of the Dependencies page, the example's POM (or parent POM) defines a property specifying the version of the dependency used by the example. These properties can be overridden if there is a need to change the dependency versions used by the example. The names of these properties are of the form com.tibco.groupId.artifactId.version where groupId and artifactId are the group id and artifact id of the dependency. For example, the property named com.tibco.com.tibco.ast.version specifies the version of the dependency with the group id of com.tibco and the artifact id of ast.