📄 ch06.htm
字号:
<TT>61: BankList* list = new BankList(myBanks.size());</TT><TT>62: CORBA::Long i;</TT><TT>63: </TT><TT>64: for (i = 0; i < myBanks.size(); i++) {</TT><TT>65: (*list)[i] = Bank::_duplicate(myBanks[i]);</TT><TT>66: }</TT><TT>67: </TT><TT>68: return list;69: }</TT> </FONT></PRE><P>Of particular interest in this class are the following highlights:</P><P><TT>BankServerImpl.cpp</TT> makes use of STL-provided algorithms and functions,as evidenced by the <TT>#include</TT> directives in lines 5 and 6.</P><P>The <TT>IsBankEqual</TT> class, occupying lines 8 through 16, is an encapsulationof a function that compares two <TT>Bank</TT> references for equality (that is, theyboth refer to the same <TT>Bank</TT> object). The equality test is performed throughthe <TT>_is_equivalent()</TT> method, which returns a <TT>TRUE</TT> (nonzero) resultif its object and the argument object indeed refer to the same object.<BLOCKQUOTE> <P><HR><B>Note:</B>According to the CORBA specification, <TT>_is_equivalent()</TT> might actually return <TT>FALSE</TT> even if two object references are equivalent. The only guarantee made by the CORBA specification is that if <TT>_is_ equivalent()</TT> returns <TT>TRUE</TT>, then the object references are equivalent; otherwise, they may or may not be equivalent. (See the CORBA specification document for more information.) <HR></BLOCKQUOTE><P>The <TT>registerBank()</TT> method (lines 28-34) simply adds the given <TT>Bank</TT>to the <TT>BankServerImpl</TT>'s internal list of <TT>Bank</TT>s (in the <TT>myBanks</TT>member). Note the use of the <TT>Bank</TT> class's <TT>_duplicate()</TT> method,which increments the <I>reference count</I> of the given <TT>Bank</TT> object byone. This indicates to the <TT>Bank</TT> object that the <TT>BankServerImpl</TT>intends to retain a reference to that object. The reference count for an object,in turn, simply maintains a count of outstanding references to that object. (You'llsee later how the <TT>BankServerImpl</TT> releases its reference to the <TT>Bank</TT>object.)</P><P>Now you'll examine the <TT>unregisterBank()</TT> method in several parts.</P><P>The first part of <TT>unregisterBank()</TT>, in lines 36-52, iterates throughthe <TT>BankServerImpl</TT>'s internal list of <TT>Bank</TT>s (again, stored in the<TT>myBanks</TT> member). The <TT>isBankEqual</TT> class discussed earlier is usedto determine equality of <TT>Bank</TT> references; in this example, the <TT>std::find_if()</TT>method uses an <TT>isBankEqual</TT> object to compare object references. This stepis necessary so that when a <TT>Bank</TT> is unregistered, the <TT>BankServerImpl</TT>can remove it from its internal list of <TT>Bank</TT>s.</P><P>In the last part of <TT>unregisterBank()</TT>, lines 54-56, the given <TT>Bank</TT>is first removed from <TT>myBanks</TT>, via the <TT>erase()</TT> method. Then <TT>BankServerImpl</TT>indicates to the <TT>Bank</TT> that it is no longer keeping a reference to that <TT>Bank</TT>by calling the <TT>_release()</TT> method. <TT>_release()</TT> is the counterpartto the <TT>_duplicate()</TT> method mentioned previously; <TT>_release()</TT> decrementsthe reference count of an object. When that object's reference count reaches zero,the object can be (but not necessarily) destroyed. Because the <TT>BankServerImpl</TT>increments a <TT>Bank</TT>'s reference count when it registers and decrements the<TT>Bank</TT>'s reference count when it unregisters, the net change of the <TT>Bank</TT>'sreference count after it has registered and later unregistered is zero.</P><P>On its own, the <TT>BankServerImpl</TT> class doesn't do anything useful. To realizeits capability, you must provide code that creates a <TT>BankServerImpl</TT> andmakes it available to other objects on the network. This is done in <TT>BankServerMain.cpp</TT>,which appears in Listing 6.4.<H4><FONT COLOR="#000077">Listing 6.4. BankServerMain.cpp.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT> 1: // BankServerMain.cpp</TT><TT> 2: </TT><TT> 3: #include "BankServerImpl.h"</TT><TT> 4: #include <iostream.h></TT><TT> 5: </TT><TT> 6: int main(int argc, char *const *argv) {</TT><TT> 7: </TT><TT> 8: // Initialize the ORB and BOA.</TT><TT> 9: CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);</TT><TT>10: CORBA::BOA_var boa = orb->BOA_init(argc, argv);</TT><TT>11: </TT><TT>12: // Create a BankServerImpl object.</TT><TT>13: BankServerImpl bankServer;</TT><TT>14: </TT><TT>15: // Notify the BOA that the BankServerImpl object is ready.</TT><TT>16: boa->obj_is_ready(&bankServer);</TT><TT>17: </TT><TT>18: // Wait for CORBA events.</TT><TT>19: cout << "BankServer ready." << endl;</TT><TT>20: boa->impl_is_ready();</TT><TT>21: </TT><TT>22: // When this point is reached, the application is finished.</TT><TT>23: return 0;24: }</TT> </FONT></PRE><P>The first thing a CORBA application must do is initialize its environment, thatis, its Object Request Broker (ORB) and Basic Object Adapter (BOA). This is accomplishedthrough the <TT>ORB_init()</TT> and <TT>BOA_init()</TT> methods in lines 8-10.</P><P>After the ORB and BOA are initialized, other CORBA objects can be created andmade available to the network. This is done on a per-object basis using the <TT>obj_is_ready()</TT>method (in lines 15-16).</P><P>The preceding code notifies the BOA that the <TT>BankServerImpl</TT> object isready to be used by other objects on the network. The BOA also provides the <TT>impl_is_ready()</TT>method, which you see used in lines 18-20.</P><P>The <TT>impl_is_ready()</TT> method notifies the BOA that the application is readyto receive events. Typically, <TT>impl_is_ready()</TT> will wait for events for animplementation-dependent period of time; usually, this is configurable by the applicationdeveloper. For instance, <TT>impl_is_ready()</TT> can process events until the applicationis interrupted, or it can terminate the application after a predetermined amountof time has elapsed--an hour, for instance--without any events being received.</P><P>Now that the <TT>BankServer</TT> interface has been implemented, you can turnyour attention to the interface that interacts with the <TT>BankServer</TT>: the<TT>Bank</TT> interface.<H3><A NAME="Heading3"></A><FONT COLOR="#000077">Implementing the Bank Interface</FONT></H3><P>The <TT>Bank</TT> interface, as you recall from Day 5, describes the servicesprovided by a <TT>Bank</TT>--generally, the manipulation of <TT>Account</TT>s withinthat <TT>Bank</TT>. The IDL for the <TT>Bank</TT> interface is defined as shown inListing 6.5.<H4><FONT COLOR="#000077">Listing 6.5. Bank.idl.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT> 1: // Bank.idl</TT><TT> 2: </TT><TT> 3: // Forward declaration of Bank interface.</TT><TT> 4: interface Bank;</TT><TT> 5: </TT><TT> 6: #ifndef Bank_idl</TT><TT> 7: #define Bank_idl</TT><TT> 8: </TT><TT> 9: // sequence of Banks</TT><TT>10: typedef sequence<Bank> BankList;</TT><TT>11: </TT><TT>12: #include "Customer.idl"</TT><TT>13: #include "Account.idl"</TT><TT>14: </TT><TT>15: // A Bank provides access to Accounts. It can create an Account</TT><TT>16: // on behalf of a Customer, delete an Account, or list the current</TT><TT>17: // Accounts with the Bank.</TT><TT>18: interface Bank {</TT><TT>19: </TT><TT>20: // This Bank's name.</TT><TT>21: attribute string name;</TT><TT>22: </TT><TT>23: // This Bank's address.</TT><TT>24: attribute string address;</TT><TT>25: </TT><TT>26: // Create an Account on behalf of the given Customer, with the</TT><TT>27: // given account type ("savings" or "checking", where case is</TT><TT>28: // significant), and the given opening balance.</TT><TT>29: Account createAccount(in Customer customer, in string</TT><TT>30: accountType, in float openingBalance);</TT><TT>31: </TT><TT>32: // Delete the given Account. If the Account is not with this</TT><TT>33: // Bank, this operation does nothing.</TT><TT>34: void deleteAccount(in Account account);</TT><TT>35: </TT><TT>36: // List all Accounts with this Bank.</TT><TT>37: AccountList getAccounts();</TT><TT>38: };</TT><TT>39:40: #endif</TT> </FONT></PRE><P>Here, you'll need to provide implementations for <TT>name()</TT> and <TT>address()</TT>--whichhave both accessor and mutator forms for the <TT>name</TT> and <TT>address</TT> attributes--alongwith <TT>createAccount()</TT>, <TT>deleteAccount()</TT>, and <TT>getAccounts()</TT>,as well as the constructor (or constructors) and destructor for this class.</P><P>After looking at <TT>BankServerImpl.h</TT> (back in Listing 6.2), nothing in <TT>BankImpl.h</TT>should be too surprising (see Listing 6.6). Again, the mapping of IDL methods toC++ methods is straightforward (although you'll notice the use of the <TT>CORBA::Float</TT>type that the IDL <TT>float</TT> type mapped to), and the <TT>BankImpl</TT> makesuse of STL in much the same way as <TT>BankServerImpl</TT>.<H4><FONT COLOR="#000077">Listing 6.6. BankImpl.h.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT> 1: // BankImpl.h</TT><TT> 2: </TT><TT> 3: #ifndef BankImpl_h</TT><TT> 4: #define BankImpl_h</TT><TT> 5: </TT><TT> 6: #include <vector></TT><TT> 7: </TT><TT> 8: #include "../Bank_s.h"</TT><TT> 9: </TT><TT>10: class BankImpl : public _sk_Bank {</TT><TT>11: </TT><TT>12: public:</TT><TT>13: </TT><TT>14: // Constructor.</TT><TT>15: //</TT><TT>16: // name - This Bank's name.</TT><TT>17: BankImpl(const char* name);</TT><TT>18: </TT><TT>19: // Destructor.</TT><TT>20: ~BankImpl();</TT><TT>21: </TT><TT>22: // These methods are described in Bank.idl.</TT><TT>23: virtual char* name();</TT><TT>24: virtual void name(const char* val);</TT><TT>25: virtual char* address();</TT><TT>26: virtual void address(const char* val);</TT><TT>27: virtual Account_ptr createAccount(Customer_ptr customer,</TT><TT>28: const char* accountType, CORBA::Float openingBalance);</TT><TT>29: virtual void deleteAccount(Account_ptr account);</TT><TT>30: virtual AccountList* getAccounts();</TT><TT>31: </TT><TT>32: protected:</TT><TT>33: </TT><TT>34: // Return the next available account number. The result is</TT><TT>35: // returned in a static buffer.</TT><TT>36: char* getNextAccountNumber();</TT><TT>37: </TT><TT>38: // Return the current date in the form "Mmm DD YYYY". The result</TT><TT>39: // is returned in a static buffer.</TT><TT>40: char* getCurrentDate();</TT><TT>41: </TT><TT>42: private:</TT><TT>43: </TT><TT>44: // Default constructor.</TT><TT>45: BankImpl();</TT><TT>46: </TT><TT>47: // This Bank's name.</TT><TT>48: char* myName;</TT><TT>49: </TT><TT>50: // This Bank's address.</TT><TT>51: char* myAddress;</TT><TT>52: </TT><TT>53: // This Bank's Accounts.</TT><TT>54: std::vector<Account_ptr> myAccounts;</TT><TT>55: </TT><TT>56: // The next available account number.</TT><TT>57: unsigned int myNextAccountNumber;</TT><TT>58: };</TT><TT>59: 60: #endif</TT> </FONT></PRE><P>You haven't seen it yet, but <TT>BankMain.cpp</TT> defines a global variable called<TT>boa</TT> (see line 14 of Listing 6.7), which is a reference to the Basic ObjectAdapter used by the application. Although the simplicity of a global <TT>boa</TT>variable makes it appropriate for a sample application, in a production applicationyou want a cleaner mechanism for sharing the reference to the BOA. For example, youcan provide a class that makes the BOA available through a static member, or youcan write class constructors to take a BOA as an argument. Regardless of how youaccomplish this, there will sometimes be a need for various objects in an applicationto access the BOA. (In this example, a <TT>BankImpl</TT> needs to call <TT>obj_is_ready()</TT>on <TT>Account</TT> objects that it creates.)<H4><FONT COLOR="#000077">Listing 6.7. BankImpl.cpp.</FONT></H4><PRE><FONT COLOR="#0066FF"><TT> 1: // BankImpl.cpp</TT><TT> 2: </TT><TT> 3: #include "BankImpl.h"</TT><TT> 4: </TT><TT> 5: #include <time.h></TT><TT> 6: #include <string.h></TT><TT> 7: #include <iostream.h></TT><TT> 8: #include <algorithm></TT><TT> 9: #include <functional></TT><TT> 10: </TT><TT> 11: #include "SavingsAccountImpl.h"</TT><TT> 12: #include "CheckingAccountImpl.h"</TT><TT> 13: </TT><TT> 14: extern CORBA::BOA_var boa;</TT><TT> 15: </TT><TT> 16: // STL-derived unary function which returns TRUE if Accounts are</TT><TT> 17: // equal.</TT><TT> 18: class IsAccountEqual : public std::unary_function<Account_ptr,</TT><TT> 19: bool> {</TT><TT> 20: public:</TT><TT> 21: IsAccountEqual(argument_type account) { myAccount = account; }</TT><TT> 22: result_type operator()(argument_type account) { return account-></TT><TT> 23: _is_equivalent(myAccount) != 0; }</TT><TT> 24: private:</TT><TT> 25: argument_type myAccount;</TT><TT> 26: };</TT><TT> 27: </TT><TT> 28: // Constructor.</TT><TT> 29: //</TT><TT> 30: // name - This Bank's name.</TT><TT> 31: BankImpl::BankImpl(const char* name) : myAccounts(),</TT><TT> 32: myName(strdup(name)), myAddress(strdup("123 Elm Street, "</TT><TT> 33: "Anyware USA 12345")), myNextAccountNumber(0) {</TT><TT> 34: </TT><TT> 35: }</TT><TT> 36: </TT><TT> 37: // Default constructor.</TT><TT> 38: BankImpl::BankImpl() : myAccounts(), myName(NULL), myAddress(NULL),</TT><TT> 39: myNextAccountNumber(0) {</TT><TT> 40: </TT><TT> 41: }</TT><TT> 42: </TT><TT> 43: // Destructor.</TT><TT> 44: BankImpl::~BankImpl() {</TT><TT> 45: </TT><TT> 46: cout << "Bank \"" << name() << "\" being destroyed." << endl;</TT><TT> 47: free(myName);</TT><TT> 48: free(myAddress);</TT><TT> 49: }</TT><TT> 50: </TT><TT> 51: char* BankImpl::name() {</TT><TT> 52: </TT><TT> 53: return CORBA::strdup(myName);</TT><TT> 54: }</TT><TT> 55: </TT><TT> 56: void BankImpl::name(const char* val) {</TT><TT> 57: </TT><TT> 58: free(myName);</TT><TT> 59: myName = strdup(val);</TT>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -