[Contents] [Previous] [Next]

Chapter 3
Naming and Binding to Objects

This chapter describes how interface names and object names are used to identify objects, the options associated with binding a client to an object implementation, and the way these object references can be manipulated. This chapter includes the following major sections:

Interface and Object Names

Binding to Objects

Operations on Object References

Widening and Narrowing Object References

Interface and Object Names

When you define an object's interface in an IDL specification, you must give it an interface name. For example, the following IDL code defines an interface named library.

interface library {
void add_book();
};
The interface name is the least specific name by which a client application can identify an object. An object name may also be used to further qualify an object. For information on obtaining interface and object names from an object reference, see below.

Interface Names

You define an object's interface name when you define the object in IDL. Server applications register interface names with a naming service. The interface name is also the name that client applications will use to bind to an object.

Object Names

In addition to the required interface name, you may specify an optional object name when instantiating an object. The ISB for C++ IDL compiler generates a NULL object name as a default parameter. An object name is required if your client application plans to bind to more than one instance of an object at a time. Object names must be assigned at the time an object is registered with the Object Activation Daemon.

Using Qualified Object Names with Servers

Imagine a library application that needs to have two library objects available; one for a library at Stanford and one for the Harvard library. You may even want to implement two separate object servers, possibly on different hosts. Each server would instantiate a library object, but each would use the Library object's constructor that accepts an object name. The following code example shows the library server code required to create separate library objects for Stanford and Harvard.

Specifying an object name when instantiating an object's implementation.

#include <lib_srv.h>
int main(int argc, char **argv)
{
// Initialize ORB and Basic Object Adaptor (BOA)
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
CORBA::BOA_var boa = orb->BOA_init(argc, argv);

// Instantiate the Stanford Library class
Library library_server("Stanford");
...
// Instantiate Harvard Library class
Library library_server("Harvard");
...
};

Using Fully Qualified Names

A client application does not have to specify an object name when binding to an object if the same service is available from multiple servers or if only one server implements the object. The ISB for C++ IDL compiler generates a NULL parameter for the object name, by default. A client application that uses two different services must specify a particular service object. The following code example specifies the Harvard library.

Using an object name.

...
// Declare the library object
library *library_object;

try {
CORBA::Object_ptr p;
WAIReturnType_t rc;
char* host = "myHost";
int port = 80;
char* uri = "/NameService/Harvard";
rc = resolveURI(host, port, uri, p);
// Narrow the reference.
library_object = library::_narrow(p);
}
// Check for errors
catch(const CORBA::Exception& excep) {
cout << "Error binding to library object" << endl;
return(0);
}
...

Binding to Objects

Before a client application can invoke methods on an object, it must obtain a reference to the object. A client application will never call the class' constructor, it will always obtain an object reference by calling a method. Then the ORB performs several functions on behalf of the application.

Client and Server on Different Hosts

If the ORB determines that the requested object implementation resides on a remote host, a TCP/IP connection will be established between the client and object server. The ORB will instantiate a proxy object for your client to use. All methods invoked on the proxy object will be packaged as requests and sent to the server on the remote host. The server on the remote host will unpack the request, invoke the desired method, and send the results back to the client.

Figure 3.1    Client and Server processes on different hosts.

Client and Server on the Same Host

If the ORB determines that the requested object implementation resides on the local host, a connection will be established between the client and object server using shared memory only if both the client and server are multithreaded. The ORB will instantiate a proxy object for your client to use. All methods invoked on the proxy object will be packaged as requests and sent to the server using shared memory.

Figure 3.2    Client and Server processes on the same host.

Client and Server in a Single Process

The previous discussions have assumed that object implementations have taken the form of a server process. While this is often the case, a client application and the object implementation can both be packaged inside a single process. When a client application binds to a service in this scenario, the ORB returns a pointer to the object implementation. That pointer will be widened to the object type used by the client application. All methods invoked on the client's object are called directly as C++ virtual functions on the object implementation. The ORB is involved only during the bind process.

Figure 3.3    Client and object implementation in the same process.

Operations on Object References

A client application can use an object reference to invoke methods on the object that have been defined in the object's IDL interface specification. In addition, ORB objects inherit methods from the class CORBA::Object that you can use to manipulate the object.

Checking for Nil References

You can use the CORBA class static method _nil to determine if an object reference is nil. This method returns 1 if the object reference passed is nil. It returns 0 if the object reference is not nil.

Method for checking for a nil object reference.

class CORBA {
...
static Boolean _nil(Object_ptr obj);
...
};

Obtaining a Nil Reference

You can obtain a nil object reference using the CORBA::Object method _nil. It returns a NULL value that is cast to an Object_ptr.

Method for obtaining a nil reference.

class Object {
...
static Object_ptr _nil();
...
};

Duplicating a Reference

A client application can use the _duplicate method to copy an object reference so that the copy can be stored in a data structure or passed as a parameter. When this method is invoked, the reference count for the object reference is incremented by one and the same object reference is returned to the caller.

The IDL compiler generates a _duplicate method for each object interface you specify. The _duplicate method shown accepts and returns a generic Object_ptr.

The method for duplicating an object reference.

class Object {
...
static Object_ptr _duplicate(Object_ptr obj);
...
};

Releasing an Object Reference

Release an object reference when it is no longer needed. One way of releasing an object reference is by invoking the CORBA::Object class method _release.

The method for releasing an object reference.

class CORBA {
class Object {
...
void _release();
...
};
};
You can also use the CORBA class method release, provided for compatibility with the CORBA specification.

The CORBA method for releasing an object reference.

class CORBA {
...
static void release();
...
};

Obtaining the Reference Count

Each object reference has a reference count that you can use to determine how many times the reference has been duplicated.When you first obtain an object reference, the reference count is set to one. Releasing an object reference will decrement the reference count by one. When the reference count reaches 0, ISB for C++ automatically deletes the object reference.

Method for obtaining the reference count.

class Object {
...
ULong _ref_count() const;
...
};

Cloning Object References

The IDL compiler generates a _clone method for each object interface that you specify. Unlike the _duplicate method, _clone creates an exact copy of the object's entire state and establishes a new, separate connection to the object implementation. The object reference returned and the original object reference represent two distinct connections to the object implementation. The following code listing shows the _clone method generated for a library interface.

The _clone method for the library class.

class library: public virtual CORBA::Object
{
public:
...
library_ptr _clone();
...
};
Platforms that support multi-threaded client applications may increase their performance by cloning an object reference for each by each thread that is created to access a particular object. See Advanced Programming Topics for information on multi-threaded applications.

Converting a Reference to a String

Object references are opaque and can vary from one ORB to another, so ISB for C++ provides an ORB class with methods that allow you to convert an object reference to a string as well as convert a string back into an object reference. The CORBA specification refers to this process as "stringification."

Methods for converting an object reference to a string and vice versa.

class ORB {
public:
// Convert an object reference to a string
char *object_to_string(Object_ptr obj);
// Convert a char* to an object reference
Object_ptr string_to_object(const char *);
...
};

Obtaining Object and Interface Names

The following code listing shows the methods provided by the Object class that you can use to obtain the interface and object names as well as the repository id associated with an object reference. The interface repository is discussed in the Dynamic Interfaces chapter of this guide.

Methods for obtaining the interface name, object name and repository id.

class Object {
...
const char *_interface_name() const;
const char *_object_name() const;
const char *_repository_id() const;
...
};

Object Reference Equivalence and Casting

You can check whether an object reference is of a particular type by using the _is_a method. You must first obtain the repository ID of the type you wish to check using the _repository_id method. This method returns 1 if the object is either an instance of the type represented by repository_id or if it is a sub-type. 0 is returned if the object is not of the type specified.

Method for determining the type of an object reference.

class Object {
...
Boolean _is_a(const char *repository_id);
...
};
The following code listing shows the _is_equivalent method which you can use to check if two object references are equivalent. This method returns 1 if the references are equivalent. This method returns 0 if the references are not identical.

Method for comparing object references.

class Object {
...
Boolean _is_equivalent(Object_ptr other_object);
...
};
You can use the _hash method shown below to obtain a hash value for an object reference. While this value is not guaranteed to be unique, it will remain consistent through the lifetime of the object reference.

The _hash method.

class Object {
...
ULong _hash(ULong maximum);
...
};

Determining the Location and State of Bound Objects

Given a valid object reference, your client application can use the method shown below to retrieve the current state of the bind for that object. The method returns 1 if the object is bound and 0 if the object is not bound.

The method for querying the state of the bind for an object reference.

class Object {
public:
...
Boolean _is_bound() const;
...
};
The following code listing shows two methods your client application can use to determine the location of a bound object implementation.

Methods for determining the location of an object implementation.

class Object {
virtual Boolean _is_local() const;
Boolean _is_remote() const;
...
};
NOTE: If the referred object is in the same process, _is_local returns TRUE.

Widening and Narrowing Object References

Converting an object reference's type to a super-type is called widening. The process of converting an object reference's type from a general super-type to a more specific sub-type is called narrowing. ISB for C++ maintains a typegraph for each object interface so that narrowing can be accomplished by the object's _narrow method. If the _narrow method determines it is not possible to narrow an object to the type you request, it will return NULL.

Narrowing.

// MsgClient.cpp
#include "SendMsg_c.hpp"
#include <iostream.h>
#include <NameUtil.hpp>

int main(int argc, char* const* argv) {
try {
// Initialize the ORB.
CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);
SendMsg::Hello_var hi;
// Find a reference to the Hello service.
CORBA::Object_ptr p;
WAIReturnType_t rc;
char* host = "myHost";
int port = 80;
char* uri = "/NameService/Howdy";
rc = resolveURI(host, port, uri, p);
// Narrow the reference.
hi = SendMsg::Hello::_narrow(p);
// Call a method provided by the service.
cout << hi->sayHello() << endl;
} catch (CORBA::SystemException& e) {
cerr << e << endl;
return(1);
}
return(0);
}
The _narrow method constructs a new C++ object and returns a pointer to that object. When you no longer need the object, you must release the object reference returned by _narrow as well as the object reference you passed as an argument.


[Contents] [Previous] [Next]

Last Updated: 02/03/98 15:29:25


Copyright © 1997 Netscape Communications Corporation