This section focuses on using the Current interface in VisiTransact-managed transactions. It includes information about how to gain access to a VisiTransact-managed transaction with Current, and begin, rollback, and commit the transaction using the methods in the Current interface. It also explains how transactional objects can share in a VisiTransact-managed transaction.
1 The transaction originator requests that Object A performs the doWork() method.
2 Object A requests that Object B performs the doMoreWork() method.VisiTransact-managed transactions are made possible with the Current object. The Current interface defines methods that simplify transaction management for most applications.The Current interface is supported by a pseudo object whose behavior depends upon, and may alter, the transaction context associated with the invoking thread. Because Current is not a CORBA object, it cannot be accessed remotely.A new transaction created with the begin() method is associated with the specific thread that called the method. A thread can be associated with only one transaction at a time. If a thread exits, or if the transaction originator's thread returns without completing the transaction, then any active transaction left associated with the thread will timeout and be rolled back.
1 Call the ORB resolve_initial_references() method. This method obtains a reference to the Current object.
2 When you narrow to CosTransactions::Current, you specify your use of the original set of methods provided by the CosTransactions module. When you narrow to VISTransactions::Current, you specify the original set and the extensions to the Current interface provided by VisiTransact.See “Extensions to the Current interface” for descriptions of VisiTransact extensions to the Current interface.// To use OMG-compliant methods and behavior
CORBA::Object_var
obj = orb->resolve_initial_references("TransactionCurrent");
CosTransactions::Current_var
current = CosTransactions::Current::_narrow(obj);
// To use OMG behavior on CosTransactions methods and also use the
// additional VisiTransact methods
CORBA::Object_var
obj = orb->resolve_initial_references("TransactionCurrent");
VISTransactions::Current_var
current = VISTransactions::Current::_narrow(obj);
• When a user calls send_deferred() during a transaction, the resultant behavior is indeterminate.This is because in Visibroker for Java implementation looks for a transaction service instance only upon the first transaction related call (for example, Current::begin()).The Current interface offers several methods for managing the current thread or context's transaction. The table below describes these methods.See Extensions to the Current interface for descriptions of VisiTransact extensions to the Current interface.If you use get_control(), suspend() or resume(), it might affect checked behavior. For more information, see “How does the VisiTransact Transaction Service ensure checked behavior?”.As shown in the following example, you can use the methods shown in the table above to perform actions with VisiTransact-managed transactions. This example shows the MyBank interface for the transactional object which defines the withdraw() method.The next example shows an example of an originator beginning a transaction and calling the withdraw() method on the MyBank transactional object. Then the originator either commits or rolls back the transaction....
// get object reference to my object implementation
MyBank_var bank = MyBank::_bind();
// start a transaction
current->begin();
if(bank->withdraw(10, 444))
{
// invoke a CORBA request
current->commit(0);
}
else
{
current->rollback();
}
...If you have a process and want to use multiple threads in the same transaction, you must pass the transaction context to each of the threads. In the typical scenario, you will start with a thread that has the transaction context—either because it is the originator and invoked Current::begin(), or because an operation passed the transaction context to it (implicitly or explicitly) and it needs to propagate that context to the other threads. This can be achieved by making the transaction's Control object available to the other threads and they can invoke Current::resume() specifying that Control object. Note that VisiTransact cannot provide checked behavior in this case.You can manage multiple transactions within a thread; however, a thread can have only one active transaction at a time. The suspend() method is used to disassociate the current context, and resume() is used to associate another context. The table in “Working with the Current interface and its methods” describes the methods used to implement multiple transactions within a thread.The following example shows an example of an object that originates multiple transactions from within a thread. This example illustrates that the MyBank_impl::withdraw() method can suspend the transaction in which the method was called, start a new transaction, and then resume the earlier transaction.CORBA::Boolean MyBank_impl::withdraw( CORBA::Long accountNo,
CORBA::Float amount)
{
try
{
// check to see if a transaction has been started
CORBA::Object_var
obj = orb->resolve_initial_references("TransactionCurrent");
CosTransactions::Current_var
current = CosTransactions::Current::_narrow(obj);
// Suspend the current transaction. If there is no current transaction,
// the control will be null.
CosTransactions::Control_var control = current->suspend();
// start a new transaction
try
{
current->begin();
// do your logic
current->commit(0);
}
catch(...)
{
// resume earlier transaction
current->resume(control);
throw;
}
}
catch(..) { }
}By default, the first time you start a transaction with begin() an instance of the VisiTransact Transaction Service is found using the Smart Agent. For details on the Smart Agent, see the VisiBroker Developer's Guide.You can control the instance of the VisiTransact Transaction Service used with arguments passed to ORB_init(), or by how you set the VISTransactions::Current interface arguments. The Current arguments will override any arguments passed to ORB_init(). The arguments will only take effect for subsequent transactions that use Current::begin().
• Host Name. The Smart Agent will find any available VisiTransact Transaction Service instance that is located on the specified host.
• VisiTransact Transaction Service Name. The Smart Agent will find the named VisiTransact Transaction Service instance anywhere on the network.
• IOR. VisiTransact uses the specified IOR for the requested Transaction Service (CosTransactions::TransactionFactory) to locate the desired instance of a Transaction Service implementation on the network. This argument enables VisiTransact to operate without the use of a Smart Agent (osagent).
The following example shows how to specify an instance of the VisiTransact Transaction Service by name using the ots_name argument of the VISTransactions::Current interface.To enable implicit propagation, a participant must be a transactional object—it must inherit from CosTransactions::TransactionalObject or define the OTSPolicy object with either the REQUIRE or ADAPT value. To enlist another participant in a transaction, the object enlisting the other participant must have a transaction associated with the current thread.
•
• If a new transaction is started using Current::begin().
• If a transactional object context has been associated with the thread using Current::resume().If a participant requires a transaction, it should verify that a transaction is not currently in progress before beginning a new transaction. If a participant attempts to begin a new transaction when a transaction is already running, the VisiTransact Transaction Service throws a CosTransactions::SubtransactionsUnavailable exception. A participant that begins a new transaction must also rollback or commit the transaction before returning.CORBA::Boolean MyBank_impl::withdraw( CORBA::Long accountNo,
CORBA::Float amount)
{
// get ORB instance
CORBA::ORB_ptr orb = CORBA::ORB_init();
// get Current reference
CORBA::Object_var
obj = orb->resolve_initial_references("TransactionCurrent");
CosTransactions::Current_var
current = CosTransactions::Current::_narrow(obj);
CORBA::Boolean startFlag = 0;//use to signal creation of the transaction
CORBA::Boolean status = 0;
try
{
// check to see if a transaction has been started
if(current->get_status() == CosTransactions::StatusNoTransaction)
{
current->begin();
startFlag = 1; //we started and now own the current transaction
}
if(balance(accountNo) > amount)
{
// withdraw logic
...
status = 1;
}
}
catch(...) { }
if(startFlag && status)
{
current->commit();
}
else if(startFlag)
{
current->rollback();
}
return status;
}When using Current, only an originator can terminate the transaction with commit() or rollback(). In this case, if a participant does not want the transaction to commit, it can use the rollback_only() method from the Current interface. When the rollback_only() method is called by a participant, the transaction associated with the target object is modified so that the only possible outcome is to rollback the transaction.When invoking rollback_only(), the CosTransactions::NoTransaction exception is raised if there is no transaction in progress. The following example shows how a participant would use the rollback_only() method....
CosTransactions::Current_var current;
current->rollback_only();
...A participant can obtain information about the current transaction such as its transaction name or transaction status using methods in the Current interface. The following table discusses these methods.
The get_status() method can return one of the following values:VisiTransact has an extended interface that provides arguments for specifying an instance of the VisiTransact Transaction Service, as well as additional methods. See “Discovering an instance of the VisiTransact Transaction service” for information on the VISTransactions::Current arguments. The following table shows the methods in the VisiTransact-extended Current interface in the VISTransactions.idl file. For more information about the Current interface, see Current interface in the VisiBroker for C++ API Reference.
Enables its caller to pass a user-defined informational transaction name. For example, this helps with diagnostics because the user-defined transaction name is included in the value returned by the get_transaction_name() method. The name also helps with administration, because the Console will report the name in the detailed information about an outstanding transaction. Returns a PropagationContext which can be used by one VisiTransact Transaction Service domain to export a transaction to a new VisiTransact Transaction Service domain. Registers a Resource for a recoverable object. This method is a shortcut for using the Control and Coordinator objects to register a Resource for a recoverable object. It returns a Recovery Coordinator object that can be used to help coordinate recovery. Most applications will not normally call this method. See “Coordinating transaction completion with Resource objects” for information about Resources. Provides the object transaction ID (otid) through the Current interface as a convenience. This avoids going to the Coordinator and looking through a PropagationContext. The otid is used to identify a transaction to a recoverable object. Most applications will not normally call this method.