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

Specifying Bind Options

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 library object introduced in Chapter 2 was given the name "library" in the IDL specification.


interface library {
void add_book();
};
The interface name is the least specific name by which an object can be identified when a client application invokes the _bind method. 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 page 3-14.

Interface Names

You define an object's interface name when you define the object in IDL. The interface name will be registered with the VisiBroker osagent, when the BOA::object_is_ready method is called by the server that implements the object. 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 VisiBroker IDL compiler generates a NULL object name as a default parameter. The use of 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, described in Chapter 4.

Using Qualified Object Names with Servers

Consider the library example from Chapter 2 and imagine that you need 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. shows the use of the default constructor. shows the library server changes that you would need to make to create separate library objects for Stanford and Harvard.

The following example shows the default use of an object's constructor:


#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 Library class

Library library_server();


orb->obj_is_ready(&library_server);

...

};

The following example shows 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 Harvard Library class

Library library_server("Harvard");

...


// Or


// Instantiate the Stanford Library class

Library library_server("Stanford");

...


orb->obj_is_ready(&library_server);

};

Using Fully Qualified Names

Your client application is not required to specify an object name when binding to an object if the same service is available from multiple servers or if there is only one server that implements the object. The VisiBroker IDL compiler generates a NULL parameter for the object name, by default.

Expanding the library example to represent two different libraries will require that you modify the client application's _bind invocation to specify a particular library object. shows the original client code used to bind to a default object. shows how you would modify the client application to specify an object name with the _bind call.

The following example shows tThe use of the _bind method without an object name:


...

// Declare the library object

library *library_object;


try {

// Locate object and return a pointer to it

library_object = library::_bind();

} // Check for errors

catch(const CORBA::Exception& excep) { cout << "Error binding to library object" << endl;

return(0);

} ...

The following example shows the modified _bind method, using an object name:


...

// Declare the library object

library *library_object;

try {

// Locate object and return a pointer to it

library_object = library::_bind("Harvard");

}

// Check for errors

catch(const CORBA::Exception& excep) {

cout << "Error binding to library object" << endl;

return(0);

}

...

Binding to Objects

Before your client application can invoke methods on an object, it must first obtain a reference to the object using the _bind method.

Note: Your client application will never call the class' constructor, it will always obtain an object reference using the static _bind method.

The _bind Process

When your client application invokes the _bind method, the ORB performs several functions on behalf of your 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.

The following figure shows 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.

The following figure shows Client and Server processes on the same host.

Client and Server in the 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 your client application invokes a bind in this scenario, the ORB will return a pointer to the object implementation itself. That pointer will be widened to the object type used by your client application. All methods invoked on your client's object will get called directly as C++ virtual functions on the object implementation. The ORB will be involved only during the bind process.

Specifying Bind Options

This section describes options that you can use to control the behavior of the _bind method. shows the _bind method generated for the library interface by the IDL compiler. The default value for all of the parameters is NULL.


class library

{

static library_ptr _bind(

const char *object_name = NULL,

const char *host_name = NULL,

const CORBA::BindOptions* opt = NULL);

...

};

The interface name specified in the interface specification becomes the name of the class. The use of the object_name parameter is discussed on page 3-2.

Host Name

In addition to the object name, your client application can specify a particular host it wishes to use for the object implementation. This can be useful if your application knows that a particular object implementation is located on a particular host. If you do not specify a host name, the ORB will locate a host that meets all of the other bind parameters.

BindOptions

Figure 3-1 shows the BindOptions structure, used for the third parameter to the _bind method, which enables you to control various aspects of the connection between the client application and the object implementation. If the third parameter is NULL, the default bind options will be used. Each of the structure's members will be discussed in turn.


struct BindOptions {

CORBA::Boolean defer_bind;

CORBA::Boolean enable_rebind;

CORBA::Long max_bind_tries;

CORBA::ULong send_timeout;

CORBA::ULong receive_timeout;

CORBA::ULong connection_timeout;

}; Figure 3-1 The BindOptions structure.

Deferring Binds

When you set defer_bind to 1, the _bind method creates a proxy object (if necessary) and returns an object reference to your client application. A connection will not be established with the object implementation until your client application actually invokes a method on the object. If you set defer_bind to 0, then the connection will be established when _bind is invoked.

The default behavior is to establish the connection at the time the _bind method is invoked.

Enabling Re-Binds

If the connection between your client application and the object implementation fails because of a network error, VisiBroker will automatically attempt to re-bind to the server process or a replica of that server. This fault tolerant processing is described in Chapter 5. If you wish to enable this re-binding process, you must set enable_rebind to 1. If you wish to prevent this re-binding process, set enable_rebind to 0.

The default _bind behavior is to attempt to re-bind to the server if an error occurs.

Maximum Bind Attempts

Object implementations may be registered with the Object Activation Daemon, described in Chapter 4, so that an object server process is automatically launched when your client binds to the object. You can set max_bind_tries to specify the number of attempts the oad should make to launch the server process.

The default oad behavior is to make no more than five attempts to launch a server process.

Send Time-outs

You set send_timeout to specify the number of seconds your client application will wait for a request to be delivered to an object server. If the time-out period expires before the message is delivered to the object server, a CORBA::NO_RESPONSE exception is raised.

By default, send_timeout is set to 0, which indicates that your client application wishes to block indefinitely.

Receive Time-outs

You set receive_timeout to specify the number of seconds your client application will wait for a response to be received from an object server. If the time-out period expires before the message is received from the object server, a CORBA::NO_RESPONSE exception is raised.

By default, receive_timeout is set to 0, which indicates that your client application wishes to block indefinitely.

Connection Time-outs

You set the connection_timeout option to specify the number of seconds your client application will wait for a connection to be established with an object server. If the time-out period expires before a connection is established, a CORBA::NO_IMPLEMENT exception is raised.

By default, connection_timeout is set to 0 to indicate that your client application wishes to use the default connection time-out.

Scope of BindOptions

VisiBroker allows you to specify three distinct levels of BindOptions. You can specify the options for each invocation of the _bind method, for a particular object reference or for all invocations of _bind by your client application.

Process-Level BindOptions

VisiBroker provides a global BindOptions structure that contains default values for the _bind method. These defaults are used if you do not explicitly specify a BindOptions parameter when you invoke the _bind method. The following example shows the static methods you can use to query and set these defaults.


class Object {

static const BindOptions *_default_bind_options();

static void _default_bind_options(const BindOptions&);

...

};

Bind-Level BindOptions

You can override the default, process-level bind options by passing a new BindOptions parameter when you invoke the _bind method.These new options will remain in effect for the life of the object reference returned by _bind, regardless of any changes to the process-level bind options.

Object-Level BindOptions

You can change bind options after you have invoked the _bind method. shows a method you can use on the object reference returned by _bind. This method allows you to change send and receive time-out values for any valid object reference. If you change the connection time-out and a re-bind occurs, the new connection time-out value will be apply. The bind options you set remain in effect for this object reference for as long as the reference is valid.

The following example shows the method for setting object-level bind options:


class Object {

...

void _bind_options(const CORBA::BindOptions& opt);

...

};

Operations on Object References

The object reference returned to your client application by the _bind method represents an ORB object. Your client application can use the object reference to invoke methods on the object that have been defined in the object's IDL interface specification. In addition, there are methods that all ORB objects inherit 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 shown 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.

The following example shows the 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 shown. It returns a NULL value that is cast to an Object_ptr.


class Object {

...

static Object_ptr _nil();

...

};

Duplicating a Reference

Your 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.


class Object {

...

static Object_ptr _duplicate(Object_ptr obj);

...

};

};

Releasing an Object Reference

You should 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.


class CORBA {

class Object {

...

void _release();

...

};

};

You may also use the CORBA class method _release, which is provided for compatibility with the CORBA specification.


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 by invoking _bind, the reference count is set to one. Releasing an object reference will decrement the reference count by one. Once the reference count reaches 0, VisiBroker automatically deletes the object reference. Figure 3-17 shows the method for retrieving 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 will create an exact copy of the object's entire state and establish a new, separate connection to the object implementation. The object reference returned and the original object reference will represent two distinct connections to the object implementation. Figure 3-18 shows the _clone method generated for the library interface introduced in Chapter 2.


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 Chapter 8 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 VisiBroker 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." Figure 3-19 shows these conversion methods.

Note: Only object references representing persistent objects can be converted to a string. Any attempt to convert a transient object reference to a string will fail. Use the _is_persistent method to ensure that an object reference represents a persistent object before calling the object_to_string method.

The following example shows the 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

Figure 3-20 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 Chapter 9 of this guide.


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.


class Object {

...

Boolean _is_a(const char *repository_id);

...

};

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.

The following example shows the method for comparing object references.


class Object {

...

Boolean _is_equivalent(Object_ptr other_object);

...

};

You can use the _hash method shown in Figure 3-23 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.


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 in Figure 3-26 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 following example shows the method for querying the state of the bind for an object reference.


class Object {

public:

...

Boolean _is_bound() const;

...

};

shows two methods your client application can use after a successful _bind invocation to determine the location of the object implementation.

The following example shows 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.

Obtaining the Current BindOptions

Given a valid object reference, your client application can use the method shown in Figure 3-26 to retrieve the bind options currently in effect for that object.


class Object {

...

const CORBA::BindOptions _bind_options() const;

...

};

Widening and Narrowing Object References

Converting an object reference's type to a super-type is called widening. Figure 3-27 shows an example of widening a library pointer to an Object pointer. The pointer lib can be cast as an Object pointer because the library class inherits from the Object class.

library		*lib;
Object *obj;

lib = library::_bind();
obj = (Object *)lib;
The process of converting an object reference's type from a general super-type to a more specific sub-type is called narrowing. VisiBroker 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.

library		*lib;
library *libtwo;
Object *obj;

lib = library::_bind();
obj = (Object *)lib;

libtwo = library::_narrow(obj);
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.


[Preface] [Chapter 1] [Chapter 2] [Chapter 3] [Chapter 4] [Chapter 5] [Chapter 6]
[Chapter 7] [Chapter 8] [Chapter 9] [Chapter 10] [Chapter 11] [Chapter 12] [Appendix A]