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.