📄 ch06.htm
字号:
<TT> 60: }</TT><TT> 61: </TT><TT> 62: char* BankImpl::address() {</TT><TT> 63: </TT><TT> 64: return CORBA::strdup(myAddress);</TT><TT> 65: }</TT><TT> 66: </TT><TT> 67: void BankImpl::address(const char* val) {</TT><TT> 68: </TT><TT> 69: free(myAddress);</TT><TT> 70: myAddress = strdup(val);</TT><TT> 71: }</TT><TT> 72: </TT><TT> 73: Account_ptr BankImpl::createAccount(Customer_ptr customer,</TT><TT> 74: const char* accountType, CORBA::Float openingBalance) {</TT><TT> 75: </TT><TT> 76: Account_ptr newAccount;</TT><TT> 77: </TT><TT> 78: if (strcmp(accountType, "savings") == 0) {</TT><TT> 79: </TT><TT> 80: // Create a new SavingsAccountImpl object for the Account.</TT><TT> 81: cout << "BankImpl: Creating new SavingsAccount for "</TT><TT> 82: "Customer " << customer->name() << "." << endl;</TT><TT> 83: newAccount = new SavingsAccountImpl(getNextAccountNumber(),</TT><TT> 84: getCurrentDate(), openingBalance, customer, 10.0);</TT><TT> 85: } else if (strcmp(accountType, "checking") == 0) {</TT><TT> 86: </TT><TT> 87: // Create a new CheckingAccountImpl object for the Account.</TT><TT> 88: cout << "BankImpl: Creating new CheckingAccount for "</TT><TT> 89: "Customer " << customer->name() << "." << endl;</TT><TT> 90: newAccount = new CheckingAccountImpl(getNextAccountNumber(),</TT><TT> 91: getCurrentDate(), openingBalance, customer);</TT><TT> 92: } else {</TT><TT> 93: </TT><TT> 94: // Invalid Account type; do nothing.</TT><TT> 95: cout << "BankImpl: Customer " << customer->name() <<</TT><TT> 96: " requested invalid Account type \"" << accountType</TT><TT> 97: << "\"." << endl;</TT><TT> 98: return Account::_nil();</TT><TT> 99: }</TT><TT>100: </TT><TT>101: // Add the created Account at the end of the list and return it.</TT><TT>102: ::boa->obj_is_ready(newAccount);</TT><TT>103: myAccounts.push_back(Account::_duplicate(newAccount));</TT><TT>104: return newAccount;</TT><TT>105: }</TT><TT>106: </TT><TT>107: void BankImpl::deleteAccount(Account_ptr account) {</TT><TT>108: </TT><TT>109: std::vector<Account_ptr>::iterator first = myAccounts.begin();</TT><TT>110: std::vector<Account_ptr>::iterator last = myAccounts.end();</TT><TT>111: IsAccountEqual predicate(account);</TT><TT>112: </TT><TT>113: std::vector<Account_ptr>::iterator matchedAccount = std::</TT><TT>114: find_if(first, last, predicate);</TT><TT>115: if (matchedAccount == last) {</TT><TT>116: </TT><TT>117: // Invalid Account; do nothing.</TT><TT>118: cout << "BankImpl: Ignored attempt to delete invalid " <<</TT><TT>119: "Account." << endl;</TT><TT>120: return;</TT><TT>121: }</TT><TT>122: cout << "BankImpl: Deleting Account \"" << account-></TT><TT>123: accountNumber() << "\"." << endl;</TT><TT>124: </TT><TT>125: // Delete the given Account.</TT><TT>126: myAccounts.erase(matchedAccount);</TT><TT>127: account->_release();</TT><TT>128: }</TT><TT>129: </TT><TT>130: AccountList* BankImpl::getAccounts() {</TT><TT>131: </TT><TT>132: AccountList* list = new AccountList(myAccounts.size());</TT><TT>133: CORBA::Long i;</TT><TT>134: </TT><TT>135: for (i = 0; i < myAccounts.size(); i++) {</TT><TT>136: (*list)[i] = Account::_duplicate(myAccounts[i]);</TT><TT>137: }</TT><TT>138: </TT><TT>139: return list;</TT><TT>140: }</TT><TT>141: </TT><TT>142: // Return the next available account number. The result is returned</TT><TT>143: // in a static buffer.</TT><TT>144: char* BankImpl::getNextAccountNumber() {</TT><TT>145: </TT><TT>146: static char accountNumber[16] = "Account ";</TT><TT>147: </TT><TT>148: sprintf(accountNumber + 7, "%08u", myNextAccountNumber++);</TT><TT>149: </TT><TT>150: return accountNumber;</TT><TT>151: }</TT><TT>152: </TT><TT>153: // Return the current date in the form "Mmm DD YYYY". The result is</TT><TT>154: // returned in a static buffer.</TT><TT>155: char* BankImpl::getCurrentDate() {</TT><TT>156: </TT><TT>157: static char currentDate[12] = " ";</TT><TT>158: </TT><TT>159: time_t ltime;</TT><TT>160: time(&ltime);</TT><TT>161: char* ctimeResult = ctime(&ltime);</TT><TT>162: </TT><TT>163: memcpy(currentDate, ctimeResult + 4, 3);</TT><TT>164: memcpy(currentDate + 4, ctimeResult + 8, 2);</TT><TT>165: memcpy(currentDate + 7, ctimeResult + 20, 4);</TT><TT>166: </TT><TT>167: return currentDate;168: }</TT> </FONT></PRE><P>Here are the highlights from <TT>BankImpl.cpp</TT> (refer to Listing 6.7).</P><P>Notice that when a string is returned by a CORBA method, as in the first formof the <TT>name()</TT> method (see lines 51-54), it must be done in the proper manner.When a CORBA method returns a string, it must use the <TT>CORBA::strdup()</TT> method(note that this is not the same as the standard library <TT>strdup()</TT> method)on that string. Using <TT>CORBA::strdup()</TT> allows the application to free thememory used by the string after it has been marshaled back to the caller. The precedingexample demonstrates this for the <TT>name()</TT> accessor method; you will noticethat the <TT>address()</TT> accessor method is similar.</P><P>Also, examine the last few lines of the <TT>createAccount()</TT> method (see lines101-104).</P><P>Notice that when a new <TT>Account</TT> object is created, you must inform theBOA that the object is ready, again using the <TT>obj_is_ready()</TT> method. (Thisis why the <TT>BankImpl</TT> object needs visibility to the BOA.) Note also thatbefore the newly created <TT>Account</TT> object is passed back to the caller, itsreference count is incremented by the <TT>_duplicate()</TT> method. This is importantbecause when an object reference is passed back to a caller (either as a return valueor as an <TT>out</TT> or <TT>inout</TT> parameter), the reference count is decremented.Therefore, when returning a CORBA object reference in this manner, you must always<TT>_duplicate()</TT> the object reference before returning it.</P><P>The remainder of <TT>BankImpl.cpp</TT> will be recognized by C++ programmers orremembered from <TT>BankServerImpl.cpp</TT>. Like <TT>BankServerImpl</TT>, the <TT>BankImpl</TT>must also be accompanied by a bit of extra code to start up the <TT>BankImpl</TT>and make it available to the rest of the network. This code can be seen in Listing6.8.<H4><FONT COLOR="#000077">Listing 6.8. BankMain.cpp.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT> 1: // BankMain.cpp</TT><TT> 2: </TT><TT> 3: #include "BankImpl.h"</TT><TT> 4: </TT><TT> 5: #include <iostream.h></TT><TT> 6: </TT><TT> 7: #include "../BankServer_c.h"</TT><TT> 8: </TT><TT> 9: CORBA::BOA_var boa;</TT><TT>10: </TT><TT>11: int main(int argc, char *const *argv) {</TT><TT>12: </TT><TT>13: // Check the number of arguments; there should be exactly one</TT><TT>14: // (two counting the executable name itself).</TT><TT>15: if (argc != 2) {</TT><TT>16: cout << "Usage: Bank <bankname>" << endl;</TT><TT>17: return 1;</TT><TT>18: }</TT><TT>19: </TT><TT>20: // Assign the bank name to the first argument.</TT><TT>21: const char* bankName = argv[1];</TT><TT>22: </TT><TT>23: // Initialize the ORB and BOA.</TT><TT>24: CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);</TT><TT>25: ::boa = orb->BOA_init(argc, argv);</TT><TT>26: </TT><TT>27: // Create a Bank object.</TT><TT>28: BankImpl bank(bankName);</TT><TT>29: </TT><TT>30: // Notify the BOA that the BankImpl object is ready.</TT><TT>31: ::boa->obj_is_ready(&bank);</TT><TT>32: </TT><TT>33: // Locate a BankServer object and register with it.</TT><TT>34: BankServer_var bankServer;</TT><TT>35: try {</TT><TT>36: bankServer = BankServer::_bind();</TT><TT>37: } catch (const CORBA::Exception& ex) {</TT><TT>38: </TT><TT>39: // The bind attempt failed...</TT><TT>40: cout << "BankImpl: Unable to bind to a BankServer." << endl;</TT><TT>41: cout << ex << endl;</TT><TT>42: return 1;</TT><TT>43: }</TT><TT>44: try {</TT><TT>45: bankServer->registerBank(&bank);</TT><TT>46: } catch (const CORBA::Exception& ex) {</TT><TT>47: </TT><TT>48: // The registerBank() attempt failed...</TT><TT>49: cout << "BankImpl: Unable to register Bank." << endl;</TT><TT>50: cout << ex << endl;</TT><TT>51: return 1;</TT><TT>52: }</TT><TT>53: </TT><TT>54: // Wait for CORBA events.</TT><TT>55: cout << "Bank \"" << bankName << "\" ready." << endl;</TT><TT>56: ::boa->impl_is_ready();</TT><TT>57: </TT><TT>58: // When this point is reached, the application is finished.</TT><TT>59: return 0;60: }</TT> </FONT></PRE><P>A key difference between <TT>BankServerMain.cpp</TT> and <TT>BankMain.cpp</TT>is that, whereas a <TT>BankServer</TT> doesn't need to locate and connect to otherobjects, a <TT>Bank</TT> needs to locate a <TT>BankServer</TT> and register withit. This is accomplished by the code in lines 33-43.</P><P>The <TT>BankServer::_bind()</TT> call attempts to bind, or connect, to a <TT>BankServer</TT>object. Optionally, <TT>_bind()</TT> can specify a name of an object to connect to,but when the name is omitted, <TT>_bind()</TT> will attempt to connect to any availableobject of the requested type. If the <TT>_bind()</TT> attempt fails, a <TT>CORBA::Exception</TT>is thrown, then caught, and its contents printed to the console.<BLOCKQUOTE> <P><HR><B>Note:</B>Although the <TT>_bind()</TT> functionality is available in several ORB products (including IONA Technologies' Orbix and Visigenic's VisiBroker products), it is not included in the CORBA standard. In any case, the <TT>_bind()</TT> mechanism is probably unsuitable for large-scale production systems anyway; you'll most likely want to use the CORBA Naming Service or Trader Service to locate objects on the network. (See Day 12 for a more in-depth discussion of the CORBAservices.) <HR></BLOCKQUOTE><P>If the application successfully binds to a <TT>BankServer</TT> object, it willregister the <TT>Bank</TT> with it, as in lines 44-52.</P><P>Here, <TT>registerBank()</TT> is the remote method of the <TT>BankServer</TT>interface. As with all remote methods, <TT>registerBank()</TT> can throw a <TT>CORBA::Exception</TT>,and thus this exception should be caught by the application. In this case, the exceptionis caught and an error message printed.</P><P>A <TT>Bank</TT> object is essentially a factory for <TT>Account</TT> objects,and the implementations of the <TT>Account</TT> and its derived interfaces are whatyou will study next.<H3><A NAME="Heading4"></A><FONT COLOR="#000077">Implementing the Account Interface</FONT></H3><P>The <TT>Account</TT> interface defines the capabilities of a generic bank account,such as the withdrawal and deposit of funds. The IDL for the <TT>Account</TT> interfaceis defined as shown in Listing 6.9.<H4><FONT COLOR="#000077">Listing 6.9. Account.idl.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT> 1: // Account.idl</TT><TT> 2: </TT><TT> 3: // Forward declaration of Account interface.</TT><TT> 4: interface Account;</TT><TT> 5: </TT><TT> 6: #ifndef Account_idl</TT><TT> 7: #define Account_idl</TT><TT> 8: </TT><TT> 9: // sequence of Accounts</TT><TT>10: typedef sequence<Account> AccountList;</TT><TT>11: </TT><TT>12: #include "Customer.idl"</TT><TT>13: </TT><TT>14: // An Account is an entity owned by a Bank and held by a Customer</TT><TT>15: // (or multiple Customers). An Account has a balance which can be</TT><TT>16: // affected by deposits and withdrawals.</TT><TT>17: interface Account {</TT><TT>18: </TT><TT>19: // This Account's account number.</TT><TT>20: readonly attribute string accountNumber;</TT><TT>21: </TT><TT>22: // This Account's creation date.</TT><TT>23: readonly attribute string creationDate;</TT><TT>24: </TT><TT>25: // This Account's current balance.</TT><TT>26: readonly attribute float balance;</TT><TT>27: </TT><TT>28: // Return a list of Customers who hold this Account.</TT><TT>29: CustomerList getCustomers();</TT><TT>30: </TT><TT>31: // Withdraw the given amount from this Account. Returns the new</TT><TT>32: // account balance.</TT><TT>33: float withdraw(in float amount);</TT><TT>34: </TT><TT>35: // Deposit the given amount into this Account. Returns the new</TT><TT>36: // account balance.</TT><TT>37: float deposit(in float amount);</TT><TT>38: };</TT><TT>39: 40: #endif</TT> </FONT></PRE><P>Thus, you'll need to provide implementations for the following methods: <TT>accountNumber()</TT>,<TT>creationDate()</TT>, and <TT>balance()</TT>, which are accessors for the <TT>accountNumber</TT>,<TT>creationDate</TT>, and <TT>balance</TT> attributes, respectively, as well as<TT>getCustomers()</TT>, <TT>withdraw()</TT>, and <TT>deposit()</TT>, along withthe constructor (or constructors) and destructor for this class. The header filefor the implementation (<TT>AccountImpl.h</TT>) appears in Listing 6.10, followedby the implementation itself (<TT>AccountImpl.cpp</TT>) in Listing 6.11.<H4><FONT COLOR="#000077">Listing 6.10. AccountImpl.h.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT> 1: // AccountImpl.h</TT><TT> 2: </TT><TT> 3: #ifndef AccountImpl_h</TT><TT> 4: #define AccountImpl_h</TT><TT> 5: </TT><TT> 6: #include "../Account_s.h"</TT><TT> 7: </TT><TT> 8: class AccountImpl : public _sk_Account {</TT><TT> 9: </TT><TT>10: // Allow CheckingAccountImpl and SavingsAccountImpl access to the</TT><TT>11: // protected constructor.</TT>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -