The example below shows the contents of the quickstart.idl file which defines the three objects required for the quick start example—Bank, Account, and Storage.
The interface specification you create in IDL is used by the VisiBroker ORB's idl2cpp compiler to generate C++ stub routines for the client application, and skeleton code for the objects. The stub routines are used by the client program for all method invocations. You use the skeleton code, along with code you write, to create the server programs that implement the objects.
The file named transfer.C contains the implementation of the transaction originator, which also happens to be the client program. As discussed in
“Overview of transaction processing” the transaction originator is not always the client program. The
transfer client program performs a single VisiTransact-managed transaction (see
“Creating and propagating VisiTransact-managed transactions” for details). For information on how to manage transactions in other ways, see
“Other methods of creating and propagating transactions”.
The ORB_init() function will parse both ORB arguments and VisiTransact arguments, removing them from the
argv vector before returning.
Before the transfer client program can invoke methods on the transactional (Account) objects, it must first use the
_bind() method to establish a connection to the Bank object. The implementation of the
_bind() method is generated automatically by the
idl2cpp compiler. The
_bind() method requests the ORB to locate and establish a connection to the Bank object.
The following example shows how to bind to the Bank object as specified in the bank_name parameter passed at the command line when the
transfer client program is started. Notice how a
_var is used to facilitate memory management.
The next example shows how to obtain a VisiTransact-managed transaction. First an object reference is obtained for the TransactionCurrent object using the CORBA::ORB::resolve_initial_references() method. The Current object returned from this method is then narrowed to the specific
CosTransactions::Current object using the
narrow() method. See the VisiBroker documentation for a full description of the
resolve_initial_references()and
narrow() methods.
To perform work that is managed by VisiTransact, you must first begin a transaction using the Current interface's
begin() method. Only one transaction can be active within a thread at a time. The following example shows how to begin a VisiTransact-managed transaction.
Once you bind to the Bank object, you can obtain a reference to the transactional (Account) objects specified when the transfer program is started. Within the
transfer program, these references are obtained using the
get_account() method in the Bank interface. The example below shows the relevant code from the
transfer program.
In the above example, the transfer client program loops through its input arguments (received at the command line when the program started), and calls
get_account() for each source and destination account name entered. If the account name entered is valid, the Bank object returns a corresponding Account object. See
“Implementing the Bank object and its get_account() method” for details on the Bank object's
get_account() method.
Notice that if an invalid account name was entered, an error message is printed and the value of the commit variable is set to false. Likewise, if a system exception is raised when performing the invocation of
get_account(), an error message is printed and the value of the
commit variable is set to false. See
“Committing or rolling back the transaction” to find out how the
commit variable is used for transaction completion.
Once the transfer client program has established a connection with the source and destination Account objects, the
debit() and
credit() methods of the
Account interface can be invoked for each source/destination/amount triplet that was entered when the
transfer program was started.
The debit() and
credit() methods are invoked from within the
transfer program's main
try() clause using the information returned to the
src and
dst variables by the invocation of the
get_account() method shown in the previous example. The next example shows the parts of the
try() clause that invoke
credit() and
debit().
The example below shows how the transfer program uses the
commit variable to decide whether to commit or rollback the transaction. If the
commit variable is 1 (true), the transaction is committed. If the
commit variable is 0 (false), the transaction is rolled back. In the next example, the 0 sent to commit() means that heuristics will not be reported. See
“Transaction completion” for information about heuristics.
The following example shows the outer try and
catch statements for the
transfer client program. Notice how these statements are used to detect any failures (CORBA or application exceptions), print a message, and return.
The bank_server program performs these steps in the
main routine:
The argc and
argv parameters passed to the
ORB_init() methods are the same parameters that are passed to the
main routine. These parameters can be used to specify options for the ORB.
Next, the myPOA that is to be used to activate the Storage object is created. The
bank_server program then obtains a Storage object, and retrieves account information from it. Using the account information, the
bank_server program instantiates the Bank object. Lastly, the
bank_server program calls the
orb->run() method to start the event loop that
receiveclient requests.
The BankImpl class that you implement is derived from the
POA_quickstart::Bank class that was generated by the
idl2cpp compiler. The following example shows the
BankImpl class.
The BankImpl interface defines its constructor and destructor. The constructor creates a Bank object with the name provided when the
bank_server program is started (
bank_name). It also creates an instance of
AccountRegistry which is used to keep trace of all instantiated Account objects. The account names are obtained from the Storage object.
The next example shows the Bank object's get_account() method. Note that the
get_account() method performs a check to see if the account exists, else it will create a new account. If it does not, a
NoSuchAccount exception is thrown.
The AccountImpl class that you implement is derived from the
POA_quickstart::Account class that was generated by the
idl2cpp compiler. Refer to the first code example in the previous section. The
account_poa has a policy OTS_POLICY_TYPE of REQUIRE defined, hence all objects that are activated on this poa will need to be transactional objects.
The _account_poa was created during the construction of the BankImpl object. Refer to the first code sample in
“Implementing the Bank object and its get_account() method”. In the
get_account() function, whenever a new account is needed it will be activated using the
_account_poa. This makes the Account object a transactional object.
As shown in the following example, the AccountImpl class defines its constructor which creates an Account object with the
account_name and
storage parameters provided by the Bank object.
As shown in the next example, the Account class also implements a markForRollback() method. When invoked, this method calls
rollback_only() to force the transaction originator to rollback the transaction.
Notice how the markForRollback() method obtains a handle to the
TransactionCurrent object, and then narrows to a Current object so that it can call
current->rollback_only(). Since the Account object is not the transaction originator, it cannot invoke
rollback()—with VisiTransact-managed transactions, only the transaction originator can complete the transaction.
The transfer.C file that you created and the generated
quickstart_c.C file are compiled and linked to create the client program. The
bank_server.c file that you created, along with the generated
quickstart_s.C,
quickstart_c.C, and
bank.C files, are compiled and linked to create the
bank_server program. Because Current is a pseudo object and VisiTransact-managed transactions use the Current object, the client program and server programs must also be linked with the VisiTransact
its_support library.
The <install_dir>/examples/vbe/its/ directory of your VisiTransact release contains a
Makefile for this example. This directory also contains a
itsmk file which is included by the
Makefile and defines all site-specific settings. You may need to customize the
itsmk file. The
itsmk file assumes that VisiTransact has been installed in the default installation directory for VisiBroker.
The Visual C++ nmake command, a standard facility, runs the
idl2cpp compiler and then compiles each file.
In this example, make is the standard UNIX facility.
Start the storage_server program at the command line by typing:
Start the bank_server program at the command line by typing:
Make sure the PATH environment variable includes the path to the VisiTransact directory (where the binaries are located). On Solaris, make sure the
LD_LIBRARY_PATH environment variable includes the path to the VisiTransact shared libraries.
Start the transfer program at the command line with the name of the bank, followed by the source account, destination account, and amount of money you wish to transfer.
Running the transfer client program with “
MyBank Paul John 20” results in the following output from the
transfer client program: