The first step in developing a CORBA application is to define the interfaces to its distributed application objects. We can define these interfaces using the CORBA Interface Definition Language (IDL).
Essentially, the IDL specification of an interface lists the names and types of operations that:
Our application manages three types of CORBA object, representing accounts, checking accounts, and banks. We declare the interfaces to all three objects within the same CORBA module, BankingDemo
:
module BankingDemo {
interface account {
// details follow
};
interface checkingAccount : account {
// details follow
};
interface bank {
// details follow
};
};
The following subsections describe the IDL declarations for each of the three interfaces. You can find the complete IDL description for the bank demo in
(example-edit-file "corba/bank/bank.idl")
We begin with the IDL definition of the interface to an account
object.
// in module BankingDemo
interface account {
readonly attribute string name;
readonly attribute long balance;
void credit (in unsigned long amount);
exception refusal {string reason;};
void debit (in long amount)
raises (refusal);
};
The name of an account is recorded in its name
attribute. The state of an account is recorded in its balance
attribute. To keep things simple, we use CORBA long
values to represent monetary amounts.
To prevent clients from directly altering the account's name or balance, these attributes are declared as readonly
attributes. The operations credit
and debit
are provided to allow updates to an account's balance
attribute.
The operation credit
adds a non-negative amount to the current account balance.
Next comes an exception declaration:
exception refusal {string reason;};
This declares a named exception, refusal
, that the debit operation uses to signal errors. The refusal
exception is declared to contain a reason
field that documents the reason for failure in the form of a string
.
The operation debit
subtracts a given amount from the current balance, provided doing so does not make the account balance negative. Qualifying debit
by the phrase
raises (refusal)
declares that invoking this operation may raise the exception refusal
. Although a CORBA operation may raise any CORBA system exception, its declaration must specify any additional user-defined CORBA exceptions that it might raise.
This completes the IDL declaration of the account
interface.
The bank application also manages another sort of account called a checking account. While an ordinary account must maintain a positive balance, a checkingAccount
may be overdrawn up to an agreed limit.
We use IDL's notion of interface inheritance to capture the intuition that a checking account is a special form of account:
// in module BankingDemo
interface checkingAccount : account {
readonly attribute long limit;
};
The declaration checkingAccount : account
specifies that the interface checkingAccount
inherits all the operations and attributes declared in the account
interface. The body of the definition states that a checkingAccount
also supports the additional limit
attribute.
The fact that checkingAccount
inherits some operations from account
does not imply that the methods implementing those operations need to be inherited too. We will exploit this flexibility to provide a specialized debit
method for checkingAccounts
.
We can now design the interface of a bank
object. The intention is that a bank associates customer names with accounts, with each name identifying at most one account. A client is able to open accounts for new customers and to retrieve both accounts and checking accounts for existing customers from the persistent store. If the client attempts to open a second account under the same name, the bank should refuse the request by raising an exception. Similarly, if the client attempts to retrieve an account for an unknown customer, the bank should reject the request by raising an exception.
The IDL definition of the bank interface captures some of these requirements:
// in module BankingDemo
interface bank {
readonly attribute string name;
exception duplicateAccount{};
account openAccount (in string name)
raises (duplicateAccount);
checkingAccount openCheckingAccount(in string name,
in long limit)
raises (duplicateAccount);
exception nonExistentAccount{};
account retrieveAccount(in string name)
raises (nonExistentAccount);
void closeAccount (in account account);
};
The name of a bank is recorded in its name
attribute.
The operation openAccount
is declared to take a CORBA string
and return an account
. Because account
is defined as an interface, and not a type, this means that the operation will return a
reference
to an account
object. This illustrates an important distinction between ordinary values and objects in CORBA: while members of basic and constructed types are passed by value, objects are passed by reference.
The qualification raises
(duplicateAccount
) specifies that openAccount
can raise the user-defined exception duplicateAccount
, instead of returning an account. (The exception duplicateAccount
has no fields.)
The operation openCheckingAccount
is similar to openAccount
, but takes an additional argument, limit
, which represents the account's overdraft limit.
The operation retrieveAccount
looks up the account (or checking account), if any, associated with a customer name, returning an object reference of interface account
. The operation may raise the exception nonExistentAccount
to indicate that there is no account under the supplied name.
The last operation, closeAccount
, closes an account by deleting it from the bank's records.
Because checkingAccount
inherits from account
, a checkingAccount
object may be used wherever an account
object is expected, whether as the actual argument, or the result, of an operation. For instance, this means that we can use closeAccount
to close checking accounts as well as accounts; and to use retrieveAccount
to fetch checking accounts as well as accounts.
The complete IDL definition for the bank can be found in file bank.idl
.
Developing Component Software with CORBA - 7 Aug 2017