Thus far, we’ve explored the Naming Service on the surface but have yet to actually dig under the hood to see how to make everything function. This next section further examines the implementation details of the Naming Service, builds a small simple application, and then builds a wine cellar management application.
As with all CORBAservice specifications, the principle deliverable for the Naming Service is a collection of interfaces described using CORBA IDL. The Naming Service IDL, contained in Listing 30.1, has two important interfaces: NamingContext and BindingIterator . Let’s stop for a moment and examine the interfaces. They are relatively self-explanatory and should be easy to understand. Once you have a feeling for the interfaces, we’ll discuss them in detail.
LISTING 30.1 THE CosNaming MODULE CONTAINS ALL CODE FOR THE CORBA NAMING SERVICE
module CosNaming {
typedef string Istring;
struct NameComponent { Istring id;
Istring kind;
};
typedef sequence <NameComponent> Name;
enum BindingType {nobject, ncontext};
struct Binding {
Name binding_name;
BindingType binding_type;
};
typedef sequence <Binding> BindingList;
interface BindingIterator;
interface NamingContext {
enum NotFoundReason { missing_node, not_context, not_object};
exception NotFound { NotFoundReason why;
Name rest_of_name;
};
exception CannotProceed { NamingContext cxt;
Name rest_of_name;
};
exception InvalidName{};
exception AlreadyBound {};
exception NotEmpty{};
void bind(in Name n, in Object obj)
raises(NotFound, CannotProceed, InvalidName, AlreadyBound);
void rebind(in Name n, in Object obj)
raises(NotFound, CannotProceed, InvalidName);
void bind_context(in Name n, in NamingContext nc) raises(NotFound, CannotProceed, InvalidName, AlreadyBound);
void rebind_context(in Name n, in NamingContext nc) raises(NotFound, CannotProceed, InvalidName);
Object resolve (in Name n)
raises(NotFound, CannotProceed, InvalidName);
void unbind(in Name n) raises(NotFound,
CannotProceed, InvalidName);
NamingContext new_context();
NamingContext bind_new_context(in Name n) raises(NotFound, AlreadyBound, CannotProceed, InvalidName);
void destroy() raises(NotEmpty);
void list(in unsigned long how_many, out BindingList bl,
out BindingIterator bi);
};
interface BindingIterator {
boolean next_one(out Binding b);
boolean next_n(in unsigned long how_many,out BindingList bl);
void destroy();
};
};
Before diving into the interfaces themselves, we need to cover two important terms. The purpose of the Naming Service is to allow objects to be associated with a name and for those objects to be discovered using their name. The task of associating a name graph
with an object is called binding. The task of discovering an object by using the name graphs is called resolving.
As you may have guessed when examining the interfaces, most of the functionality of the Naming Service is present in the NamingContext interface. This interface exposes methods for binding and resolving objects, along with other housekeeping methods. The following list provides an explanation of these interfaces, starting with the bind() and resolve() methods and then moving on to everything else:
• bind() The bind() operation, which is probably the first operation you’ll invoke, is obviously used to bind an object to a name graph. It accepts as a parameter both a name graph and the object that’s to be bound to that graph. The name graph is formed by creating an array of NameComponent objects, where the first object in the array is the highest level descriptor, and the last object is the most specific. A
NameComponent object is formed using two strings: a logical name and a description of the data.
• rebind() The rebind() operation creates a binding of a name graph and an object in the naming context, even if the name is already bound in the context.
• resolve() Once an object is bound to a name graph, it is discovered using the resolve() operation. This operation accepts a name graph as a parameter and searches for an object associated with the same graph. If no object can be found, an exception is raised.
• bind_context() and rebind_context() The bind_context() and rebind_context() operations allow for the binding of an object that’s actually a name graph itself. This context can then be discovered using the traditional
resolve() operation and allows for the creation of interconnected namespaces.
• new_context() and bind_new_context() A unique context is used to represent an independent namespace. To create a new context object, the new_context() operation is used. If, when you’re creating a new context, it’s best served by
associating it with an existing context. The bind_new_context() operation accepts a name graph as a parameter and returns a new context bound to the specified graph.
• unbind() The unbind() operation accepts a name graph as a parameter and removes it from the context.
• destroy() If a naming context is no longer needed, it can be removed from existence by invoking its destroy() operation.
• list() In addition to querying the naming context for specific objects, you can also simply browse all name graphs. Applications in which human users are required to choose some object, can graphically render the name graphs using the list() operation and then resolve the actual object once a unique graph is chosen. The list() operation allows access to all graphs. Unlike other operations, which simply return the requested data, the list() operation accepts two out parameters that are populated using the data contained in the name graphs and an in parameter indicating the amount of data to be returned. The first out parameter is a BindingList object that references an array of name graphs. The number of graphs referenced by the
BindingList object is specified by the in parameter. If there are additional name graphs not referenced by the BindingList object, they are accessed through the second out parameter, a BindingIterator object.
• BindingIterator Because naming contexts may reference large numbers of name graphs, the BindingIterator object is used to obtain these graphs in smaller chunks. It exposes a next_one() method that populates an out parameter with the next available name graph. In addition, a next_n() method populates an out
parameter with the number of name graphs specified by the in parameter.