Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Advanced CORBA Programming wit C++ - M. Henning, S. Vinoski.pdf
Скачиваний:
65
Добавлен:
24.05.2014
Размер:
5 Mб
Скачать

IT-SC book: Advanced CORBA® Programming with C++

tmstat2 = CCS::Thermostat::_narrow(o);

// OK

Testing for nil other than with CORBA::is_nil

CCS::Thermostat_ptr tmstat = CCS::Thermostat::_nil();

if

(tmstat) ...

//

Illegal!

if

(tmstat != 0) ...

//

Illegal!

if

(tmstat != CCS::Thermostat::_nil()) ... // Illegal!

if

(!CORBA::is_nil(tmstat)) ...

// OK

7.7 Pseudo-Objects

So far, we have skirted the issue of how a client actually obtains an object reference. To address this, we must look at pseudo-objects and examine how a client initializes the ORB and how it gets its initial object references.

The CORBA specification defines a number of interfaces to the ORB run time. Because CORBA supports several different implementation languages, these interfaces must be specified in a language-independent way. IDL is perfectly suited to this; a single IDL specification describes an interface for all supported implementation languages.

To avoid polluting the global namespace, interfaces defined by CORBA are placed in the CORBA module. Following is a small part of the contents of that module.

module CORBA {

// PIDL

interface ORB {

 

// ...

 

};

 

// ...

 

};

 

Note the PIDL comment for the module. It stands for pseudo-IDL. Pseudo-IDL definitions are like ordinary IDL definitions and use the same data types, operations, attributes, and so on. There is almost no syntactic difference between PIDL and IDL— but see the definition of ORB_init on page 242.

Why bother with PIDL? The answer is that some interfaces to the ORB cannot be implemented as ordinary CORBA objects but instead must be implemented by library code that ships with the ORB. In particular, interfaces to the ORB run time must be implemented this way, and the PIDL comment marks such interfaces.

Interfaces defined in PIDL are subject to a number of restrictions.

Pseudo-interfaces do not implicitly inherit from Object.

220

IT-SC book: Advanced CORBA® Programming with C++

Pseudo-interfaces cannot be passed as arguments to operations on ordinary interfaces. (The TypeCode pseudo-interface is exempt from this rule—see Section 16.3.3.)

Operations on pseudo-interfaces cannot be invoked via the Dynamic Invocation Interface (DII).

Pseudo-interfaces do not have definitions in the Interface Repository.

Pseudo-interfaces may have a special-purpose language mapping that deviates from the normal rules.

All this sounds terribly restrictive, but it is not because there is no need ever to use any of the restricted features for pseudo-objects. The one noticeable difference between PIDL and ordinary objects is that PIDL objects may have a special-purpose language mapping. We point out such differences as we discuss the relevant PIDL. Usually, differences from the normal mapping rules exist to avoid restricting ORB implementers in their range of choices or to make the relevant interface easier to use.

7.8 ORB Initialization

Before a client can do anything, it must initialize the ORB run time. The initialization call is defined in the CORBA module:

module CORBA {

ORBid;

// PIDL

typedef string

arg_list;

typedef sequence<string>

interface ORB;

// Forward declaration

ORB ORB_init(inout arg_list argv, in ORBid orb_identifier);

// ...

};

The CORBA module defines an operation ORB_init, which initializes the ORB run time and returns a pseudo-reference to the ORB object. Note that the ORB_init operation is not declared inside an interface. This is legal in PIDL, whereas in normal IDL it would be an error (operation declarations can occur only inside an interface).

Before we discuss the details of ORB_init, let us take a look at its C++ mapping:

namespace CORBA {

 

// ...

 

ORB_ptr ORB_init(

argc,

int &

char **

argv,

const char *

orb_identifier = ""

);

 

// ...

 

221

IT-SC book: Advanced CORBA® Programming with C++

}

The ORB_init function expects three arguments.

argc is the number of entries in argv.

argv is the command-line argument vector passed to main. orb_identifier is a vendor-specific string (defaulted to the empty string).

A typical client main looks something like this:

int

main(int argc, char * argv[])

{

CORBA::ORB_ptr orb;

try {

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

}

catch (...) {

cerr << "Cannot initialize ORB" << endl; exit(1);

}

// Use ORB...

CORBA::release(orb);

return 0;

}

ORB_init receives a reference to argc and an argv vector from the client and examines argv for ORB-specific options beginning with -ORB. ORB_init removes any ORB-specific options from argv so when the call returns, the argument vector contains only the remaining options that concern the application rather than the ORB.

The orb_identifier argument to ORB_init identifies the particular ORB to initialize. This behavior is useful if an application needs to initialize more than one ORB run-time environment. The application can also use orb_identifier to select a particular set of configuration values or quality-of-service parameters. CORBA does not precisely specify the effects of the orb_identifier argument, so you must consult your ORB's documentation for details.

The default orb_identifier is the empty string, which instructs the implementation to use whatever default behavior has been configured. If orb_identifier is the empty string, ORB_init scans the argument vector for an option of the form -ORBid arg. If this option is present, the value of arg determines the behavior. If orb_identifier is a non-empty string and if -ORBid is also used, orb_identifier overrides the value of the -ORBid option.

222

IT-SC book: Advanced CORBA® Programming with C++

ORB_init returns a reference to the ORB pseudo-object. Clients and servers always obtain their first object reference this way; the ORB pseudo-object contains operations that can be called to obtain further references. Note that you must eventually release the returned reference (pseudo-references must be released just as normal references are). Releasing the ORB reference instructs the ORB run time to clean up. This means that you must release the ORB reference last because other ORB-related calls may no longer work after the run time has cleaned up.

Note that you cannot use the ORB before the code has entered main because you must pass argc and argv parameters to ORB_init. In particular, you cannot make CORBA-related calls from constructors for global or static C++ objects. Do not try to cheat by passing dummy argc and argv parameters to ORB_init before the code has entered main; the result may be a core dump. For example, ORB_init could fail catastrophically because it may itself depend on side effects from global constructors in the ORB run-time libraries.

In general, you should ban global objects from your code. As shown in [11], global objects inevitably cause more problems than they solve. However, the ORB pseudoobject typically must be accessible from anywhere in your source code. A good way to make the object globally accessible is to use the Singleton pattern [4].

7.9 Initial References

After the client has initialized the ORB, it can obtain further references by invoking operations on the ORB interface:

module CORBA { // PIDL // ...

interface ORB {

string object_to_string(in Object obj); Object string_to_object(in string str); // ...

}; // ...

};

The ORB interface contains two operations that can be used to create and obtain initial references.

object_to_string This operation converts a reference into a printable string—for example, for storing a reference on disk.

string_to_object This operation converts a stringified reference back into an object reference.

The C++ mapping for these operations is as follows:

223

IT-SC book: Advanced CORBA® Programming with C++

namespace CORBA {

//...

class ORB { public:

char * object_to_string(Object_ptr p); Object_ptr string_to_object(const char * s);

};

//...

}

A client uses these operations by invoking them on the ORB pseudo-object.

7.9.1 Conversion from String to Reference

The following example shows how a client obtains a reference to our climate controller object from the command line.

// Initialize ORB.

CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);

//Assume argv[1] is a stringified reference to a controller. CORBA::Object_ptr obj;

try {

obj = orb->string_to_object(argv[1]);

}

catch (...) {

cerr << "Bad format for stringified reference" << endl; exit(1);

}

//Check that reference is non-nil.

if (CORBA::is_nil(obj)) {

cerr << "Passed reference is nil" << endl; exit(1);

}

//Narrow to controller. CCS::Controller_ptr ctrl; try {

ctrl = CCS::Controller::_narrow(obj);

}

catch (...) {

cerr << "Narrow failed" << endl; exit(1);

}

//Don't need base interface anymore. CORBA::release(obj);

//Was the reference of the correct type? if (CORBA::is_nil(ctrl)) {

cerr << "Argument is not a controller reference" << endl; exit(1);

}

224

IT-SC book: Advanced CORBA® Programming with C++

//

//Use controller reference...

//Clean up

CORBA::release(ctrl);

// Narrow calls _duplicate

CORBA::release(orb);

// Clean up

There is quite a bit happening in this example, so we cover the code in stages.

Note that pseudo-operations such as string_to_object and _narrow can throw exceptions. We cover exception handling in detail in Section 7.15. For now, our exception handling is to print an error message and exit whenever any exception is thrown at all.

Keep in mind that calling exit is fine for operating systems such as UNIX, in which the kernel guarantees recovery of resources allocated to a process. However, in DOS or Windows, this strategy will eventually get you into trouble because memory allocated in DLLs is not necessarily recovered by the operating system when a process exits. If you are writing code for such an environment, you must release resources allocated to your process before you exit; otherwise, the machine will eventually run out of memory.

obj = orb->string_to_object(argv[1]);

This call converts a stringified object reference back to a reference. The returned reference has the type CORBA::Object_ptr. Because Object is at the root of the interface inheritance tree, string_to_object can return references of arbitrary interface type.

string_to_object creates a new proxy, so you must eventually release the reference again by calling CORBA::release.

If the passed string is syntactically invalid, string_to_object throws an exception.

if (CORBA::is_nil(obj)) ...

The string passed as argv[1] may be a valid reference, but that does not guarantee that it is non-nil. The client explicitly tests for this condition and complains if a nil reference is passed.

ctrl = CCS::Controller::_narrow(obj);

The client expects a reference to a climate controller (not to some other interface). The call to _narrow determines whether the passed reference is of the correct type. If _narrow returns nil, the passed reference is of the wrong type.

225

IT-SC book: Advanced CORBA® Programming with C++

_narrow creates a new proxy, so you must eventually release the returned reference again by calling CORBA::release.

_narrow raises an exception if the ORB cannot reliably determine whether the reference is of the expected type. Usually, the exception is either TRANSIENT or OBJECT_NOT_EXIST. We cover the semantics of these exceptions in Section 7.15.2.

CORBA::release(obj);

The client does not need to keep the reference obj (of type Object_ptr) after it has successfully narrowed it, so it might as well release it.

After the client has narrowed the reference to the correct type, the client can use it to invoke operations on the corresponding object.

CORBA::release(ctrl);

When the client is no longer interested in the reference, it calls CORBA::release to reclaim its resources.

CORBA::release(orb);

This is the final ORB-related call in all clients. Releasing the ORB pseudo-object instructs the run time that no further CORBA activity will take place and that all CORBA run-time resources should be released.

7.9.2 Conversion from Reference to String

The object_to_string operation converts an object reference into a string:

CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);

CCS::Controller_ptr ctrl = ...; // Get reference...

char * s; try {

s = orb->object_to_string(ctrl);

}

catch (...) {

cerr << "Cannot convert reference to string" << endl; exit(1);

}

cout << s << end;

// Print reference

CORBA::string_free(s);

// Finished with string

CORBA::release(ctrl);

// Release controller proxy

CORBA::release(orb);

// Shut down run time

object_to_string returns the stringified form of the passed reference. As always, the returned string is dynamically allocated, so the preceding code calls string_free

226