New York University

Computer Science Department

Courant Institute of Mathematical Sciences

 

Exploring CORBAservices and CORBAfacilities

       

Course Title: Application Servers                                                       Course Number: g22.3033-011

Instructor: Jean-Claude Franchitti                                                        Session: 5

 

 

By now you are very familiar with the basic mechanisms provided by CORBA to enable the development of distributed object-oriented applications. The ORB mechanism facilitates the communication between CORBA objects and enables objects to locate each other, and the POA provides the core functionality for all CORBA objects.

 

The functionality provided by the ORB and the POA alone is not nearly enough on which to build robust, enterprise-class-distributed applications. Additional capabilities would definitely be advantageous--such as directory services, persistent object capability, a transaction mechanism, user interface and presentation facilities, and so on--regardless of the industry in which they are used. Many industries--such as health care, finance, and telecommunications--require applications that are especially well-suited to CORBA, so functionality that caters to these vertical markets is a good idea. As it turns out, the OMG offers such horizontal and vertical functionality in the form of CORBAservices and CORBAfacilities.

 

You've already been introduced, albeit briefly, to CORBAservices and CORBAfacilities. Today you'll learn about these in greater detail, as well as get the chance to apply some of the CORBAservices to the Bank application you've been developing.

 


CORBAservices

 

The Object Management Architecture (OMA), of which CORBA is a part, defines a number of services that are useful to applications in general. These services range from the nearly indispensable Naming Service to higher level services such as the Transaction Service. As with all its specifications (including CORBA), the Object Management Group (OMG) does not define the implementations for these services but provides the interfaces by which the services are offered. It is up to the various CORBA product vendors to supply implementations. Note that products implementing CORBAservices are often provided separately from CORBA ORB products and that implementation of CORBAservices is not necessary for CORBA 2 compliance.

This handout briefly describes each of the CORBAservices.

Concurrency Control Service

The Concurrency Control Service provides an interface for managing concurrency in shared CORBA objects. This is done through the use of locks, several types of which are supported by the service. For example, readers-writer locks are supported, as are intention locks. Developers who have worked with multithreaded applications are probably familiar with the features provided by the Concurrency Control Service.

Event Service

The Event Service provides a mechanism through which CORBA objects can send and receive events. The service includes such features as these:

 

·        Reliable delivery, which (simply put) ensures that an event will reach its destination(s)

·        Support for push and pull models of event delivery

 

·        Anonymous messaging, when suppliers need not know the identities of event consumers, or vice versa

 

·        Event channels, a mechanism similar to publish/subscribe, through which consumers can subscribe to certain types of events

Externalization Service

The Externalization Service provides interfaces for externalizing (that is, serializing) and internalizing objects. When an object is externalized, it can be internalized within the same process or a different process. In addition, objects can be externalized into a portable file format (one that is defined with the Externalization Service Specification). One possible application for the Externalization Service is in a pass-by-value mechanism for CORBA objects.

Licensing Service

The Licensing Service enables the provider to define policies that control the use of services. The service supports three types of licensing policies:

 

·        Time enables a license to set a start date, expiration date, and duration.

 

·        Value mapping enables licensing based on units (resource usage metering, number of concurrent users, and so on).

 

·        Consumer assigns services for use by a particular user or machine.

 

Facilities like those provided by the Licensing Service will become more widely used as concepts such as pay-as-you-go or rentable software are realized. For example, an occasional user of image editing software might pay per use of a certain image filter. As a framework for electronic commerce becomes available, it is possible that you'll see more software made available in this way.

Life Cycle Service

The Life Cycle Service offers facilities for creating, deleting, copying, and moving CORBA objects. The service also supports the notion of an object factory, which is a CORBA object that creates other CORBA objects.

Naming Service

The Naming Service enables CORBA objects to register and be located by name. This service uses the notion of a naming context, which contains a set of unique names. The Naming Service also supports a federated architecture, meaning that name servers can be distributed across the network and work in conjunction with each other.

 

You recall that, as a part of the standard bind mechanism, CORBA objects are given names by which other objects can look them up. Although you can think of this feature as a miniature Naming Service, the actual Naming Service is much more scalable.

Object Trader Service

The Trader Service, like the Naming Service, enables other objects to locate CORBA objects. Rather than use a name to locate an object, a client object looks for services based on operation names, parameters, and result types.

 

The major difference between the Trader Service and the Naming Service is analogous to the difference between the yellow pages and the white pages of a telephone directory. The Naming Service can be thought of as the white pages, in which you look up a particular service if you know its exact name. The Trader Service, on the other hand, resembles the yellow pages, in which you locate a service, based on its location, function, or even name. For example, in the white pages you can look up "Bob's Dry Cleaning;" in the yellow pages you can look for all dry cleaning services in, say, Littleton, Colorado. In the Bank, an application might use the Naming Service to locate a Bank by its name (such as FirstBank) or use the Trader Service to locate objects by function (such as a bank or an ATM).

Persistent Object Service

The Persistent Object Service provides a set of interfaces for managing the persistence of objects. Typically, implementations for this service are provided by database vendors.

 

Persistent objects are objects that persist over a period of time; that is, the lifetime of the object can transcend the lifetime of any one application. While not in use, the object resides in a persistent store, such as a database or a flat file; the object can then be retrieved, or resurrected, when needed. For example, a document created by a word processor can be thought of as a persistent object because the word processor application can be closed and run again later, allowing the document to be retrieved. In a CORBA application, it will sometimes be useful to provide persistent capability to CORBA objects. For example, in the sample Bank application, the Bank objects could conceivably be persistent objects. A Bank could be resurrected as needed, and then when it is no longer processing transactions, it could be put to sleep, meaning that its state could be stored in a database until the Bank was needed again.

Property Service

The Property Service enables objects to define sets of properties, which are name/value pairs. The name in a pair is simply a CORBA string; the value is a CORBA any. Access to properties can be restricted. For example, a property can be read-only or fixed.

 

The use of properties to describe objects is becoming more widespread, particularly as object models such as JavaBeans gain momentum. A large application, or set of applications, could define a number of standard properties for its objects, thereby potentially easing management. For example, if the Bank application defined a location property for each object, the location of Banks, ATMs, Customers, and other objects could be determined in a uniform way anywhere in the application code.

Query Service

The Query Service supports the use of queries on objects. Queries can contain predicates that specify objects to act on, based on attribute values. The service also supports object indexing as well as nested queries. Query capability provides database-like semantics to CORBA objects. Just as an application can perform queries on tables and rows in a relational database, the Query Service allows an application to perform queries on CORBA objects.

Relationship Service

The Relationship Service enables the representation of relationships between objects. It provides for full constraint checking of relationship type and cardinality (one-to-many, one-to-one, and so on) and also works in conjunction with the Life Cycle Service to copy, move, and remove related objects. Managing relationships between objects is, of course, possible without the Relationship Service, but this service reduces the complexity of managing complex relationships.

Security Service

The Security Service specifies the interfaces for security features:

 

·        Identification and authentication of users, which verify that a user is who he or she claims to be.

·        Authorization and access control determine which users are enabled access to which services or objects.

·        Security auditing, which provides records of users' actions.

·        Security of communication, which includes authentication of users to services (and vice versa), integrity protection, and confidentiality protection.

·        Non-repudiation, which provides capabilities similar to those offered by digital signatures; that is, the origin of data or the receipt of data can be proven irrefutably.

·        Administration of various security policies.

 

Security is a paramount issue in a number of applications; for example, in a production bank application, virtually all aspects of the system must be made secure, from authentication and identification of customers to security of communication between banks and ATMs.

Time Service

The Time Service enables a user to obtain the current time; it can determine event ordering and can generate events based on timers.

Transaction Service

The Transaction Service provides the interfaces to support transaction capabilities. It supports flat and nested transaction models as well as external TP monitors. Transaction services can also interoperate with each other.

 

Transaction semantics are an integral part of almost every non-trivial application. For example, in the sample Bank application, to coordinate a transfer between accounts at different banks, a transaction should be initiated that would cause the banks involved either to both commit the transaction or to both abort the transaction; otherwise, inconsistent data (such as account balances) would result.


CORBAfacilities

 

CORBAfacilities cover both horizontal facilities (features useful to all types of CORBA applications across various industries) and vertical facilities (functionality that is especially useful to applications within particular vertical markets and industries). Horizontal facilities include user interface and system management facilities because this functionality is useful to most types of applications, regardless of the industry in which they are used. Vertical facilities might include, for example, general ledger and amortization functionality for use within the accounting industry, or automated shop floor control facilities for use in the manufacturing industry. Like CORBAservices, the OMG only specifies the interfaces for these facilities; the implementations, where applicable, are provided by CORBA vendors. Additionally, some CORBAfacilities only suggest interfaces to be used for particular services and types of applications.

 

Horizontal Facilities

The horizontal CORBAfacilities are categorized into four types of facilities: user interface, information management, systems management, and task management. These categories are further broken down into other facilities (listed in the next section). Again, horizontal facilities are advantageous to all types of applications, regardless of industry. For example, most applications require user interfaces, methods of information storage and retrieval, security facilities, workflow and process management, and so on.

 

User Interface Common Facilities

The User Interface Common Facilities cover all that relates to user interfaces, from the tools used to develop them to the way they are presented to the user. CORBAfacilities defines the following components of user interfaces: User Interface Style is the "look and feel" presented to the user by the application. User Interface Enablers present the user interface to the user. Enablers are grouped into the following facilities:

 

·        Rendering Management, for abstracting user interface objects

·        Compound Presentation, for displaying compound documents

·        User Support, for spell checking, online help, and so on

 

Work Management System maintains a user's work environment and consists of the user's desktop, single sign-on to the system, and information used by the user. Task and Process Automation enables users to write scripts to automate their tasks and use workflows.

 

Information Management Common Facilities

The Information Management Common Facilities consist of the following: Information Modeling deals primarily with the way data is structured.

 

Information Storage and Retrieval includes databases, information retrieval systems, and repositories.

 

Information Interchange enables the exchange of data between users and between applications, consisting of the Compound Interchange Facility, the Data Interchange Facility, and the Information Exchange Facility. Data Encoding and Representation deals with how information is stored, down to the bit level, if necessary. The primary reason for addressing this is to enable portability of data between applications, processes, hardware and software architectures, and so on.

 

Systems Management Common Facilities

The Systems Management Common Facilities provide interfaces for system administration.

 

Policy Management controls the creation, deletion, and modification of manageable components.

 

Quality of Service Management supports the selection of service levels for availability, performance, reliability, and recovery.

 

Instrumentation provides the capability to gather and analyze data regarding system load, object location, system responsiveness, and so on.

 

Data Collection includes capabilities such as logging and data archival.

 

Security provides for the management of security of system resources.

 

Collection Management enables administrators to deal with collections of objects to be managed.

 

Instance Management enables objects to be associated with other objects for management purposes.

 

Scheduling Management enables tasks to be performed in a controlled manner (for example, to occur at a certain time or as a response to a particular event).

 

Customization enables objects to be extended dynamically while retaining type safety.

 

Event Management provides for various manipulations of events in the system.

 

Task Management Common Facilities

Task Management Common Facilities support the processing of user tasks. Among the Task Management Common Facilities are the following: Workflow provides management and coordination of objects that are part of a work process, for example, a purchase process. It supports production-based workflows as well as ad hoc (coordination-based) workflows.

 

Agent supports both static and mobile agent types. Although the definition and discussion of the use of agents are beyond the scope of this handout, the agent-related facilities include the Content Service, the Communication Service, the Message Service, the Basic Information Services, the Simple Query Services, the Multi-Response Query Services, the Assertion Services, the Generation Services, the Capability Definition Services, the Notification Services, the Networking Services, the Facilitation Services, the Database Services, the Adaptation Services, the Error Correction Services, the Automatic Re-Transmission Services, the Registration Service, Security Services, and Management Services.

 

Rule Management provides for the specification and processing of rules, which in turn are based on events, conditions, and actions. Automation provides the capability to use scripts and macros to manipulate large-grained CORBA objects.

 

Vertical Market Facilities

In addition to the horizontal services and facilities offered by the OMA, there are also a number of vertical CORBAfacilities--facilities intended for the unique requirements of specific markets. Also, the OMG continually adds new Vertical Market Facilities, depending on the interest in a particular specialty area. The remainder of this section gives a brief overview of the Vertical Market Facilities specifications available at the time of this writing.

 


Note:Although now a part of the OMG's Facilities Architecture, the Vertical Market Facilities are largely being superceded by work done by the OMG's various Domain Task Forces. Each of these Task Forces produces specifications for the vertical application domain to which it is assigned.

 

 


Imagery supports the access and interchange of imagery and related data.

 

Information Superhighways consists of a set of networks, protocols, and rules, information repositories connected through these networks, and a collection of tools for transparent access to this information.

 

Manufacturing represents the integration of manufacturing functions and resources with other aspects of the business enterprise.

 

Distributed Simulation supports distributed simulations of air traffic control, video games and entertainment, and other needs.

 

Oil and Gas Industry Exploration and Production provides a foundation for defining specifications for exploration and production (E&P). Requirements for E&P include dealing with large quantities of data, complex algorithms, and long-term data storage.

 

Accounting provides an interoperable approach to accounting interfaces and seeks to remove the complexity from accounting service providers and end users.

 

Application Development covers the selection, development, building, and evolution of the applications needed to support an enterprise's information systems strategy. Mapping provides a cohesive means of manipulating the flow of data from databases through constructed analysis modules into either presentation tools or secondary data applications.

 

Enhancing the Bank Example with CORBAservices

Of course, today wouldn't be complete without a discussion and example of how to integrate CORBAservices and CORBAfacilities with the Bank example. This section will do just that. First, you'll examine which CORBAservices are of use to the Bank application; then, you'll modify the application to employ those services.

Choosing CORBAservices

Now, briefly review the available CORBAservices for a moment and analyze the suitability of each service to the Bank application:

 

·        The Concurrency Control Service. Because it is quite feasible that objects in the Bank application (particularly Banks) might be accessed by different objects simultaneously, the use of the Concurrency Control Service has merit. However, the type of concurrency used might be better serviced by the Transaction Service.

 

·        The Event Service. If the Bank application were to expand to include messages other than those used by the account update service,  the Event Service would prove beneficial.

·        The Externalization Service. Externalization of objects isn't a terribly important feature to the Bank application.

 

·        The Licensing Service. Bank services are generally not licensed, so you can safely overlook the Licensing Service for the purposes of the Bank application.

 

·        The Life Cycle Service. The Bank application would theoretically benefit from the use of the Life Cycle Service but is served well enough by the standard CORBA mechanisms for managing object life cycle.

 

 

·        The Naming Service. If the Bank application were to grow into a highly distributed system, it would benefit greatly from the use of the Naming Service. Rather than use the standard CORBA bind mechanism, you could locate Banks through a federated Naming Service.

·        The Object Trader Service. Because the Bank application components are well-known and localized, it is unlikely that components will need to locate objects based on the services they provide. The Trader Service is geared more towards applications that require richer facilities for locating services. (Had the scope of the Bank application been more extensive, it might have been worthwhile to provide the capability to look up Banks based on location, for example.)

 

·        The Persistent Object Service. The Persistent Object Service would be worthwhile, for example, to a Bank that needs to store customer and account data in persistent storage while the information is not in use.

 

·        The Property Service. Although the Property Service can be used, for example, to represent customer or account information, it is not particularly advantageous to the Bank application.

 

·        The Query Service. As it stands, the Bank application would not benefit greatly from the Query Service. However, if reporting tools were developed to work with the Bank application, the Query Service would prove useful.

 

·        The Relationship Service. For the Bank application, there is little value in using the Relationship Service to model the relationships between objects (for example, between Banks and Accounts or between Customers and Accounts). However, if new objects were added that might increase the complexity of relationships, the Relationship Service would be helpful.

 

·        The Security Service. Because a Bank needs to be a highly secure institution, the Security Service is indispensable to a production Bank application. Numerous aspects of the Security Service can be utilized, such as user identification and authorization, security auditing, communication security, and non-repudiation. The Security Service is a perfect choice for the Bank application.

 

·        The Time Service. The Time Service is valuable; it ensures that various Banks are in sync with each other with respect to time.

 

·        The Transaction Service. The Transaction Service is another service that is highly useful to a Bank application. In particular, the interoperability with a TP monitor can coordinate transactions between Accounts and between Banks.

 

Looking at the CORBAservices from the perspective of what would provide the most utility for the Bank application, the answer would probably be the Security Service and the Transaction Service. However, looking at the services from the perspective of what's readily available, a more practical choice would be the Naming Service.

Implementing the New Functionality

Deciding where to use the functionality provided by the Naming Service is easy. The Naming Service can replace the use of the standard CORBA bind mechanism; rather than bind to objects directly by name, CORBA objects can use the Naming Service to look up other objects. In the Bank application, the only object that is located in this manner is the BankServer; all other server objects (Banks and ATMs) are located through the BankServer itself. Because these changes aren't major, they fit well within the scope of this handout.

Using the CORBA Naming Service

Rather than bind directly to the BankServer using the CORBA bind mechanism, application components instead bind to a Naming Context and then use that Naming Context to resolve a BankServer by name. A Naming Context object makes the functionality of the CORBA Naming Service available to applications. Note that the Naming Context is simply a CORBA object: Its interface is expressed in IDL, and it is manipulated by an application just as any other CORBA object is.

 

New Term: A Naming Context is simply a collection of naming structures that associate names with either CORBA object references or other Naming Contexts. Taken together, these collections of associations form a hierarchical naming structure that CORBA objects use to locate other objects.

 

The first modification to the Bank application is to change the BankServer application so that it registers itself with the Naming Service. None of the changes, to either the BankServer or any other application component, need to be made in the object implementations themselves. The only changes required are in the main section of each application, where the object is created. The first such modifications, in BankServerMain.cpp, are highlighted in bold in Listing 1.

 

Listing 1. BankServerMain.cpp.

 1: // BankServerMain.cpp

 2:

 3: #include <CosNaming_c.hh>

 4:

 5: #include "BankServerImpl.h"

 6: #include <iostream.h>

 7:

 8: int main(int argc, char *const *argv) {

 9:

10:     // Check the number of arguments; there should be exactly one

11:     // (two counting the executable name itself).

12:     if (argc != 2) {

13:         cout << "Usage: BankServer <bankservername>" << endl;

14:         return 1;

15:     }

16:

17:     // Assign the BankServer name to the first argument.

18:     const char* bankServerName = argv[1];

19:

20:     // Initialize the ORB and BOA.

21:     CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

22:     CORBA::BOA_var boa = orb->BOA_init(argc, argv);

23:

24:     // Create a BankServerImpl object.

25:     BankServerImpl bankServer(bankServerName);

26:

27:     // Notify the BOA that the BankServerImpl object is ready.

28:     boa->obj_is_ready(&bankServer);

29:

30:     // Locate a Naming Service and register the BankServer object

31:     // with it.

32:     CosNaming::NamingContext_var context;

33:     try {

34:         CORBA::Object_ptr contextObj = orb->

35:                 resolve_initial_references("NameService");

36:         CosNaming::NamingContext_var context = CosNaming::

37:                 NamingContext::_narrow(contextObj);

38:     } catch (const CORBA::Exception& ex) {

39:         cout << "BankServerMain: Could not connect to Naming "

40:                 "Service:" << endl << ex << endl;

41:         return 1;

42:     }

43:     CosNaming::Name name;

44:     name.length(1);

45:     name[0].id = bankServerName;

46:     name[0].kind = "BankServer";

47:     context->bind(name, &bankServer);

48:

49:     // Wait for CORBA events.

50:     cout << "BankServer ready." << endl;

51:     boa->impl_is_ready();

52:

53:     // When this point is reached, the application is finished.

54:     return 0;

55: }

 

Note the process of binding the object to the Naming Service. Previously, a name was not required for the BankServer; now the BankServer takes its name as a command-line argument. The BankServer then locates the default Naming Context (created by the Naming Service when it is started), creates a Name entry corresponding to the BankServer object, and finally binds to the Naming Service using that Name entry. Note also that the kind of the object, which can be any arbitrary string, uses the name "BankServer".

 

Now direct your attention to the next file to be changed, BankMain.cpp, in Listing 2. Again, rather than bind directly to a BankServer, the Bank (and, similarly, the ATM) locates a BankServer object through the Naming Service. Note that when the Name object is created, it is given the ID of "BankServer1" and the kind of "BankServer". This means that the Bank expects to connect to an object whose kind is "BankServer" (which you can verify is the case in BankServerMain.cpp, Listing 1) and whose ID is "BankServer1". Because the BankServer gets its ID (also called the Name) from the command line, you'll want to start the BankServer with the argument "BankServer1" when the time comes.

Listing 2. BankMain.cpp.

 1: // BankMain.cpp

 2:

 3: #include "BankImpl.h"

 4:

 5: #include <iostream.h>

 6:

 7: #include <CosNaming_c.hh>

 8:

 9: #include "../BankServer_c.h"

10:

11: CORBA::BOA_var boa;

12:

13: int main(int argc, char *const *argv) {

14:

15:     // Check the number of arguments; there should be exactly one

16:     // (two counting the executable name itself).

17:     if (argc != 2) {

18:         cout << "Usage: Bank <bankname>" << endl;

19:         return 1;

20:     }

21:

22:     // Assign the bank name to the first argument.

23:     const char* bankName = argv[1];

24:

25:     // Initialize the ORB and BOA.

26:     CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

27:     ::boa = orb->BOA_init(argc, argv);

28:

29:     // Create a Bank object.

30:     BankImpl bank(bankName);

31:

32:     // Notify the BOA that the BankImpl object is ready.

33:     ::boa->obj_is_ready(&bank);

34:

35:     // Locate a BankServer object in the Naming Service.

36:     BankServer_var bankServer;

37:     try {

38:         CORBA::Object_ptr contextObj = orb->

39:                 resolve_initial_references("NameService");

40:         CosNaming::NamingContext_var context = CosNaming::

41:                 NamingContext::_narrow(contextObj);

42:         CosNaming::Name name;

43:         name.length(1);

44:         name[0].id = "BankServer1";

45:         name[0].kind = "BankServer";

46:         CORBA::Object_var object = context->resolve(name);

47:         bankServer = BankServer::_narrow(object);

48:     } catch (const CORBA::Exception& ex) {

49:

50:         // The bind attempt failed...

51:         cout << "BankImpl: Unable to bind to a BankServer:" << endl;

52:         cout << ex << endl;

53:         return 1;

54:     }

55:

56:     // Register with the BankServer.

57:     try {

58:         bankServer->registerBank(&bank);

59:     } catch (const CORBA::Exception& ex) {

60:

61:         // The registerBank() attempt failed...

62:         cout << "BankImpl: Unable to register Bank." << endl;

63:         cout << ex << endl;

64:         return 1;

65:     }

66:

67:     // Wait for CORBA events.

68:     cout << "Bank \"" << bankName << "\" ready." << endl;

69:     ::boa->impl_is_ready();

70:

71:     // When this point is reached, the application is finished.

72:     return 0;

73: }

 

The changes for ATMMain.cpp, similar to those in BankMain.cpp, appear in Listing 3. You will readily see that the two implementations are nearly identical.

Listing 3. ATMMain.cpp.

 1: // ATMMain.cpp

 2:

 3: #include "ATMImpl.h"

 4:

 5: #include <iostream.h>

 6:

 7: #include <CosNaming_c.hh>

 8:

 9: #include "../BankServer_c.h"

10:

11: CORBA::BOA_var boa;

12:

13: int main(int argc, char *const *argv) {

14:

15:     // Check the number of arguments; there should be exactly one

16:     // (two counting the executable name itself).

17:     if (argc != 2) {

18:         cout << "Usage: ATM <atmname>" << endl;

19:         return 1;

20:     }

21:

22:     // Assign the ATM name to the first argument.

23:     const char* atmName = argv[1];

24:

25:     // Initialize the ORB and BOA.

26:     CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

27:     ::boa = orb->BOA_init(argc, argv);

28:

29:     // Create an ATM object.

30:     ATMImpl atm(atmName);

31:

32:     // Notify the BOA that the ATMImpl object is ready.

33:     ::boa->obj_is_ready(&atm);

34:

35:     // Locate a BankServer object in the Naming Service.

36:     BankServer_var bankServer;

37:     try {

38:        CORBA::Object_ptr contextObj = orb->

39:                 resolve_initial_references("NameService");

40:         CosNaming::NamingContext_var context = CosNaming::

41:                 NamingContext::_narrow(contextObj);

42:         CosNaming::Name name;

43:         name.length(1);

44:         name[0].id = "BankServer1";

45:         name[0].kind = "BankServer";

46:         CORBA::Object_var object = context->resolve(name);

47:         bankServer = BankServer::_narrow(object);

48:     } catch (const CORBA::Exception& ex) {

49:

50:         // The bind attempt failed...

51:         cout << "ATMImpl: Unable to bind to a BankServer:" << endl;

52:         cout << ex << endl;

53:         return 1;

54:     }

55:

56:     // Register with the BankServer.

57:     try {

58:         bankServer->registerATM(&atm);

59:     } catch (const CORBA::Exception& ex) {

60:

61:         // The registerATM() attempt failed...

62:         cout << "ATMImpl: Unable to register ATM." << endl;

63:         cout << ex << endl;

64:         return 1;

65:     }

66:

67:     // Wait for CORBA events.

68:     cout << "ATM \"" << atmName << "\" ready." << endl;

69:     ::boa->impl_is_ready();

70:

71:     // When this point is reached, the application is finished.

72:     return 0;

73: }

 

The modified ATMClientMain.cpp, appearing in Listing 4, demonstrates similar changes. Again, the ATMClient searches the Naming Service for an object named "BankServer1" of type "BankServer". The remaining code for ATMClientMain.cpp is unchanged.

Listing 4. ATMClientMain.cpp.

  1: // ATMClientMain.cpp

  2:

  3: #include <iostream.h>

  4: #include <stdlib.h>

  5:

  6: #include "../Customer/CustomerImpl.h"

  7:

  8: #include <CosNaming_c.hh>

  9:

 10: #include "../Bank_c.h"

 11: #include "../BankServer_c.h"

 12: #include "../ATM_c.h"

 13:

 14: int main(int argc, char *const *argv) {

 15:

 16:     // Check the number of arguments; there should be exactly five

 17:     // (six counting the executable name itself).

 18:     if (argc != 6) {

 19:         cout << "Usage: ATMClient <name> <social security number>"

 20:                 " <address> <mother's maiden name> <PIN>" << endl;

 21:         return 1;

 22:     }

 23:

 24:     // Assign the command line arguments to the Customer attributes.

 25:     const char* name = argv[1];

 26:     const char* socialSecurityNumber = argv[2];

 27:     const char* address = argv[3];

 28:     const char* mothersMaidenName = argv[4];

 29:     CORBA::Short pin = atoi(argv[5]);

 30:

 31:     // Initialize the ORB and BOA.

 32:     CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

 33:     CORBA::BOA_var boa = orb->BOA_init(argc, argv);

 34:

 35:     // Create a Customer object.

 36:     cout << "ATMClient: Creating new Customer:" << endl;

 37:     cout << "  name: " << name << endl;

 38:     cout << "  Social Security number: " << socialSecurityNumber <<

 39:             endl;

 40:     cout << "  address: " << address << endl;

 41:     cout << "  mother's maiden name: " << mothersMaidenName << endl;

 42:     CustomerImpl customer(name, socialSecurityNumber, address,

 43:             mothersMaidenName);

 44:

 45:     // Notify the BOA that the CustomerImpl object is ready.

 46:     boa->obj_is_ready(&customer);

 47:

 48:     // Locate a BankServer object in the Naming Service,

 49:     BankServer_var bankServer;

 50:     try {

 51:         CORBA::Object_ptr contextObj = orb->

 52:                 resolve_initial_references("NameService");

 53:         CosNaming::NamingContext_var context = CosNaming::

 54:                 NamingContext::_narrow(contextObj);

 55:         CosNaming::Name name;

 56:         name.length(1);

 57:         name[0].id = "BankServer1";

 58:         name[0].kind = "BankServer";

 59:         CORBA::Object_var object = context->resolve(name);

 60:         bankServer = BankServer::_narrow(object);

 61:     } catch (const CORBA::Exception& ex) {

 62:

 63:         // The bind attempt failed...

 64:         cout << "ATMClient: Unable to bind to a BankServer:" <<

 65:                 endl;

 66:         cout << ex << endl;

 67:         return 1;

 68:     }

 69:

 70:     cout << "ATMClient: Successfully bound to a BankServer." <<

 71:             endl;

 72:

 73:     // Try to get a list of Banks and ATMs from the BankServer.

 74:     BankList_ptr banks;

 75:     ATMList_ptr ATMs;

 76:

 77:     try {

 78:         banks = bankServer->getBanks();

 79:         ATMs = bankServer->getATMs();

 80:     } catch (const CORBA::Exception& ex) {

 81:

 82:         // The attempt failed...

 83:         cout << "ATMClient: Unable to get lists of Banks and ATMs:"

 84:                 << endl;

 85:         cout << ex << endl;

 86:         return 1;

 87:     }

 88:

 89:     // Use the first Bank and the first ATM that appear in the

 90:     // lists.

 91:     if (banks->length() == 0) {

 92:

 93:         // No Banks were available.

 94:         cout << "ATMClient: No Banks available." << endl;

 95:         return 1;

 96:     }

 97:     if (ATMs->length() == 0) {

 98:

 99:         // No ATMs were available.

100:         cout << "ATMClient: No ATMs available." << endl;

101:         return 1;

102:     }

103:     Bank_var bank = (*banks)[0];

104:     ATM_var atm = (*ATMs)[0];

105:     cout << "ATMClient: Using Bank \"" << bank->name() << "\" and"

106:             << " ATM \"" << atm->name() << "\"." << endl;

107:

108:     // Do some cool stuff.

109:

110:     Account_var account;

111:     ATMCard_var atmCard;

112:

113:     try {

114:         account = bank->createAccount(&customer, "checking", 0.0);

115:     } catch (const CORBA::Exception& ex) {

116:

117:         // The createAccount() attempt failed...

118:         cout << "ATMClient: Unable to create Account." << endl;

119:         cout << ex << endl;

120:         return 1;

121:     }

122:

123:     try {

124:

125:         // Request the automatic account update service from the

126:         // Bank.

127:         bank->requestUpdateService(account);

128:     } catch (const CORBA::Exception& ex) {

129:

130:         // The requestUpdateService() attempt failed...

131:         cout << "ATMClient: Unable to create Account." << endl;

132:         cout << ex << endl;

133:         return 1;

134:     }

135:

136:     try {

137:

138:         // Print out some Account statistics.

139:         cout << "ATMClient: Opened new Account:" << endl;

140:         cout << "  account number: " << account->accountNumber() <<

141:                 endl;

142:         cout << "  creation date: " << account->creationDate() <<

143:                 endl;

144:         cout << "  account balance: " << account->balance() << endl;

145:

146:         // Ask the Bank to issue an ATMCard for the newly created

147:         // Account.

148:         cout << "ATMClient: Getting ATMCard from Bank." << endl;

149:         try {

150:             atmCard = bank->issueATMCard(pin, account);

151:         } catch (const InvalidAccountException&) {

152:

153:             // For some reason, the Account was invalid (this

154:             // shouldn't happen).

155:             cout << "ATMClient: Exception caught: Invalid Account"

156:                     << endl;

157:             return 1;

158:         }

159:

160:         // Perform some transactions on the Account through the

161:         // ATM.

162:         cout << "ATMClient: Performing transactions." << endl;

163:         try {

164:             cout << "  Depositing $250.00..." << endl;

165:             cout << "  New balance is $" << atm->deposit(atmCard,

166:                     account, pin, 250.00) << endl;

167:

168:             // This will throw an exception since we're trying to

169:             // withdraw too much.

170:             cout << "  Withdrawing $500.00..." << endl;

171:             cout << "  New balance is $" << atm->withdraw(atmCard,

172:                     account, pin, 500.00) << endl;

173:         } catch (AuthorizationException&) {

174:             cout << "ATMClient: Exception caught: Invalid PIN or "

175:                     << "No authorization (as expected)" << endl;

176:         } catch (InvalidAmountException&) {

177:             cout << "ATMClient: Exception caught: Invalid amount"

178:                     << endl;

179:         } catch (InsufficientFundsException&) {

180:             cout << "ATMClient: Exception caught: Insufficient " <<

181:                     "funds" << endl;

182:         }

183:

184:         // Perform some more transactions on the Account through

185:         // the ATM.

186:         cout << "ATMClient: Performing more transactions." << endl;

187:         try {

188:             cout << "  Depositing $500.00..." << endl;

189:             cout << "  New balance is $" <<

190:                     atm->deposit(atmCard, account, pin, 500.00) <<

191:                     endl;

192:

193:             // This will throw an exception because we're using the

194:             // wrong PIN.

195:             cout << "  Withdrawing $250.00 with incorrect PIN..."

196:                     << endl;

197:             cout << "  New balance is $" << atm->withdraw(atmCard,

198:                     account, pin + 1, 250.00) << endl;

199:         } catch (AuthorizationException&) {

200:             cout << "ATMClient: Exception caught: Invalid PIN or "

201:                     << "No authorization (as expected)" << endl;

202:         } catch (InvalidAmountException&) {

203:             cout << "ATMClient: Exception caught: Invalid amount"

204:                     << endl;

205:         } catch (InsufficientFundsException&) {

206:             cout << "ATMClient: Exception caught: Insufficient " <<

207:                     "funds" << endl;

208:         }

209:

210:         // Get rid of the Account.

211:         try {

212:             cout << "  Deleting Account." << endl;

213:             bank->deleteAccount(account);

214:

215:             // Attempt to delete the Account again, just for kicks.

216:             // This should result in an exception being thrown.

217:             cout << "  Attempting to cause an exception by " <<

218:                     "deleting Account again." << endl;

219:             bank->deleteAccount(account);

220:         } catch (const InvalidAccountException&) {

221:

222:             // Sure enough, the exception was thrown.

223:             cout << "ATMClient: Exception caught: Invalid " <<

224:                     "Account (as expected)" << endl;

225:         }

226:     } catch (const CORBA::Exception& ex) {

227:

228:         // Some operation on the Account failed...

229:         cout << "ATMClient: Error accessing Account:" << endl;

230:         cout << ex << endl;

231:         return 1;

232:     }

233:

234:     // Sleep for long enough to catch an Account update message or

235:     // two.

236:     Sleep(120000);

237:

238:     // When this point is reached, the application is finished.

239:     return 0;

240: }

 

That's it for modifications--you're now ready to run the modified code.

Running the Application

Before running anything else, you need to start the CORBA Naming Service and let it create a default Naming Context. To do this with Visigenic's implementation of the Naming Service, type the following:

 

NameExtF <factory name> <logfile>

 

For the purposes of the Bank application, the following will do just fine:

 

NameExtF NameServer naming.log

 

The output of the Naming Service application will be the Interoperable Object Reference (IOR) assigned to the Naming Service. Your output will vary but will look something like this:

 

IOR:012020203700000049444c3a6f72672e6f6d672f436f734e616d696e672f457

874656e6465644e616d696e67436f6e74657874466163746f72793a312e30002002

0000000153495680000000010101201400000069767939362e626577656c6c6e657

42e636f6d005750f8ff010000005300000001504d43000000003700000049444c3a

6f72672e6f6d672f436f734e616d696e672f457874656e6465644e616d696e67436

f6e74657874466163746f72793a312e3000200b0000004e616d6553657276657200

2000000000000000006f000000010100200e0000003135332e33362e3234302e373

90002065300000001504d43000000003700000049444c3a6f72672e6f6d672f436f

734e616d696e672f457874656e6465644e616d696e67436f6e74657874466163746

f72793a312e3000200b0000004e616d6553657276657200

 

Because you didn't modify any of the functionality, the output of all the application components will be exactly the same.

Summary

In this handout you became aware of the many CORBAservices and CORBAfacilities specified by the OMG. You also determined which of the CORBAservices are appropriate for use with the Bank  application. Finally, you modified the Bank application to use some of the features offered in the CORBA Naming Service.

 

Additional information on the CORBAservices is available from the OMG's Web site at http://www.omg.org/.

 

Q&A

Q I didn't see any mention of vertical CORBAfacilities for [insert my pet industry here]. Is the OMG neglecting us?


A
The OMG is actively working in an ever-increasing number of vertical domains. If you are interested in developing standard facility interfaces for a particular industry, you should contact the OMG for more information.


Q What is that weird-looking IOR thing anyway?


A
The Interoperable Object Reference is a string that uniquely identifies a CORBA object. The IOR is defined in such a way that any vendor's ORB can accept an IOR and resolve it, yielding the object's location. Generally, you won't need to deal with these, though occasionally they can be a convenient mechanism for objects to locate each other. Because they are plain strings, they are easily transmitted across a network, stored in a file, and so on.

Q When using the Naming Service, the application components had the ID,
"BankServer1", hardcoded. Could I make the applications search the Naming Service for a registered BankServer instead?


A
Yes. The Naming Context supports a list() operation that returns a BindingList and BindingIterator, which in turn can be used to iterate over the contents of the Naming Context. In this way, objects are located by name or by type, or the application simply uses the first object that is found. Although the Naming Service can be used for this purpose, a better choice might be to use the Trader Service, which is intended for precisely this use.

Workshop

The following section will help you test your comprehension of the material presented in this handout and put what you've learned into practice.

Quiz

1. Who defines the specifications for CORBAservices and CORBAfacilities?

2
. Who provides the implementations for CORBAservices and CORBAfacilities?

3
. What CORBAservices and/or CORBAfacilities, if any, must a vendor provide with an ORB product in order to be considered CORBA 2.0-compliant?

4
. Why are vertical market facilities useful?

Exercises

1.      Provide an overview of how the Object Trader Service could be used to replace the BankServer in the sample Bank application.

2.      Describe how the Event Service could be used within the Bank application. What would be the benefit of using this approach?

3. (Extra Credit) If you have any products available to you that implement one or more CORBAservices, try to integrate the functionality provided by a service of your choice with the sample Bank application.