Transaction boundaries are defined using the
class.com.kabira.platform.Transaction
An application implements the abstract
run
method to execute application code in a
transaction. A transaction is implicitly started when the
execute
method is called. The
execute
method calls the application provided
run
method and executes the application code in a
transaction. A transaction is terminated in the following ways:
An application can explicitly control the outcome of a transaction
by throwing the Transaction.Rollback
exception in the
run
method. The Transaction.Rollback
exception causes the current transaction to rollback. Returning normally
from the run
method causes the transaction to
commit.
The Transaction.Rollback
exception has two
variants - with and without a Throwable
cause.
A Transaction.Rollback
exception that does not
contain a Throwable
cause exception is transparently
caught by the Transaction
class, the transaction is
rolled back, and Result.ROLLBACK
is returned from the
Transaction.execute()
method.
A
exception that contains a Transaction.Rollback
cause exception is caught by the Throwable
Transaction
class, the
transaction is rolled back, and the exception is rethrown by the
Transaction class as an InvocationRunException
. The
cause
of the InvocationRunException
is set to the Throwable
exception that was set in the
Transaction.Rollback
exception. This provides a
mechanism for application code to communicate the cause of a rollback to
the caller of the Transaction.execute()
method.
Unhandled exceptions in a run
method cause the
transaction to be rolled back. They are then re-thrown unmodified.
Example 4.1, “Counting example” shows a simple counting program that demonstrates a field value being rolled back.
Example 4.1. Counting example
// $Revision: 1.1.2.1 $ package com.kabira.snippets.transactions; import com.kabira.platform.Transaction; import com.kabira.platform.annotation.Managed; /** * A simple counting program showing transactional consistency * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = A * </ul> */ @Managed class Counter { int m_count = 0; } public class Consistency { private static boolean m_commit; private static Counter m_counter; /** * Main entry point * @param args Not used */ public static void main(String[] args) { // // Create a counter object // new Transaction("Create Counter") { @Override protected void run() throws Rollback { m_counter = new Counter(); } }.execute(); // // Increment the counter and commit the transaction // m_commit = true; incrementCounter(); printCounter(); incrementCounter(); printCounter(); // // Increment the counter and rolback the transaction // m_commit = false; incrementCounter(); printCounter(); } private static void incrementCounter() { new Transaction("Increment Counter") { @Override protected void run() throws Rollback { m_counter.m_count += 1; if (m_commit == true) { return; } throw new Transaction.Rollback(); } }.execute(); } private static void printCounter() { new Transaction("Print Counter") { @Override protected void run() throws Rollback { System.out.println(m_counter.m_count); } }.execute(); } }
When run, this simple program outputs (annotation added):
Example 4.2. Counting example output
# # Initial call to execute that commits # 1 # # Second call to execute that commits # 2 # # Third call to execute that rolls back - field restored to value before call # 2
Example 4.3, “Throwable cause example” shows the use of a
Throwable
cause to communicate rollback information to
the caller of the
.Transaction.execute()
Example 4.3. Throwable cause example
// $Revision: 1.1.2.1 $ package com.kabira.snippets.transactions; import com.kabira.platform.Transaction; class Cause extends Throwable { final static long serialVersionUID = 1L; Cause(String message) { super (message); } } /** * Rollback a transaction with a Throwable exception * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = A * </ul> */ public class RollbackWithCause { /** * Main entry point * @param args Not used */ public static void main(String [] args) { try { new Transaction("Rollback") { @Override protected void run() throws Rollback { Cause cause = new Cause("rollback because of error"); throw new Transaction.Rollback(cause); } }.execute(); } catch (Transaction.InvocationRunException ex) { System.out.println("INFO: " + ex.getCause().getMessage()); } } }
When run, this simple program outputs: