Previous Up Next

Chapter 4  The Naming Service

One way for a server application to advertise an object is for the server to stringify an object reference—by calling object_to_string()2pt—and write it to, say, a file (Section 3.4.2). A client application could then read in the string, and call string_to_object() to turn it back into a proxy. This mechanism works fine as long as the client and server applications have access to a shared file system. This is likely to be the case if the client and server are running on the same computer or on the same local area network. However, it is unlikely that a wide area network will have a shared file system. For this reason, CORBA has matured over the years to support more geographically-scalable ways for a server to advertise an object. One such way, the Naming Service, is discussed in this chapter, and another way, the Trading Service, is discussed in Chapter 20.

4.1  Basic Concepts

The white pages telephone book provides a mapping from a person’s name to their contact details (address and telephone number). Likewise, the CORBA Naming Service provides a mapping from a (human-readable) name to an object’s “contact details” (an IOR). However, that is where the analogy ends. The names in a telephone book are arranged alphabetically, while the names in the Naming Service are arranged as a hierarchy (similar to how the file system in UNIX or Windows is arranged as a hierarchy).1 Each level in the Naming Service hierarchy is called a naming context (while in a UNIX file system it is called a directory and in Windows it is called a folder). A naming context is itself a CORBA object (it is defined by the CosNaming::NamingContext interface, as shown in Figure 4.1). Because CORBA objects can be accessed regardless of their location, this means that a Naming Service hierarchy could be contained inside a single server process or the hierarchy could be spread over multiple Naming Service server processes. The concept of linking several Naming Service server processes in this way is called federation. Many organizations do not make use of federation and instead use a monolithic Naming Service. However, some organizations do make use of a federated Naming Service. This is typically done to delegate administration responsibilities. For example, an organization might have a separate Naming Service process for each department or branch and then use federation to link these separate Naming Services into one logical unit that is the “company-wide” Naming Service.

#pragma prefix "" 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 { boolean next_one(out Binding b); boolean next_n(in unsigned long how_many, out BindingList bl); void destroy(); }; interface NamingContext { void bind(in Name n, in Object obj) raises(...); void rebind(in Name n, in Object obj) raises(...); void bind_context(in Name n, in NamingContext nc) raises(...); void rebind_context(in Name n, in NamingContext nc) raises(...); Object resolve(in Name n) raises(...); void unbind(in Name n) raises(...); NamingContext new_context(); NamingContext bind_new_context(in Name n) raises(...); void destroy() raises(...); void list(in unsigned long how_many, out BindingList bl, out BindingIterator bi); }; ... // interface NamingContextExt omitted for brevity };
Figure 4.1: Naming Service IDL

The functionality of the Naming Service is defined through the operations of its IDL interfaces. There are some operations that can be used to create/modify/delete a naming context hierarchy. There are other operations to bind (that is, advertise) an IOR in the Naming Service with a specified name, and yet other operations to resolve (that is, lookup) an IOR associated with a specified name.

It is common for an implementation of the Naming Service to provide some command-line utilities and/or a GUI tool that can be used to do administration tasks on the Naming Service, such as create/modify/delete a naming context hierarchy. Such administration functionality is implemented by invoking corresponding IDL operations on the Naming Service.

The CORBA specification for the Naming Service does not specify what quality of service should be offered by an implementation. Some implementations of the Naming Service hold the details of the nameIOR mappings in memory, which has the drawback that such details are lost whenever the Naming Service is killed and restarted, but has the benefit of not requiring access to persistent storage (which might be important in an embedded device). Other implementations of the Naming Service persist the nameIOR mappings in a file or database.

Most, possibly all, implementations of CORBA have a bundled implementation of the Naming Service, which means that you do not have to purchase it separately. It is possible that the Naming Service bundled with the CORBA product you are using might have a quality of service that is unsuitable for your needs. If this is the case then you could discard that Naming Service and replace it with a Naming Service from a different vendor or even implement the Naming Service yourself. However, in practice, you are likely to be content with the quality of service offered by the Naming Service bundled with the CORBA product you decide to use. The ability to “rip out and replace” an implementation of the Naming Service (or another CORBA Service) is mentioned to illustrate the flexibility of an open standard (such as CORBA) that cleanly separates specification from implementation.

4.2  Imperfections in the IDL

Although the concepts in the Naming Service are simple, unfortunately the OMG made a few poor choices when defining the IDL types. This has resulted in confusion for some developers. Such confusion rapidly disappears when the motivation for the design choices are explained. This section explains the poor design choices with the aim of helping developers avoid unnecessary confusion. Readers who will not be doing development might prefer to skip this section.

The IDL types of the Naming Service are defined in the CosNaming module. Within this module, the NamingContext interface defines the operations that can be performed on a naming context. An application can connect to the root naming context of the Naming Service by passing "NameService" as a parameter to the resolve_initial_references() operation (Section 3.4.1). The first piece of confusion likely to strike a programmer is that the parameter to this operation is "NameService" rather than "NamingService".

Most of the remaining confusion with the API of the Naming Service concerns the format of hierarchical names within the Naming Service. In hindsight, the OMG should probably have chosen to represent a hierarchical name as a string that uses "/" as a separator between naming contexts, for example, "path/in/naming/service". However, there were several perceived problems with this:

The OMG tried to resolve the string/wstring dilemma by introducing the following definition:

typedef string Istring;

The intention was that Istring2 would be used in the Naming Service API and when wstring was later introduced to IDL then the definition could be changed to:

typedef wstring Istring;

No doubt this seemed like a good idea at the time. However, it was fatally flawed because this proposed future change in the definition of Istring would have been backwards incompatible. Because of this backwards incompatibility, the change in the definition was never made. The net effect is that the IDL definitions for the Naming Service have a useless typedef definition, which confuses some people.

To avoid hard-coding use of an arbitrary syntax (for example, "/") as a hierarchical separator, the OMG decided that a hierarchical name should be represented as a sequence of components. In order to allow support for foo.txt-style components in a name, the OMG decided that each component should be a struct that contains two fields. The resulting definition of a hierarchical name is shown below:

typedef string Istring;
struct NameComponent {
	    Istring  id;   // denotes the "foo" part of "foo.txt"
	    Istring  kind; // denotes the "txt" part of "foo.txt"
typedef sequence<NameComponent> Name;

The result is certainly flexible, but it is also over-engineered. Most people do not need all this flexibility and become frustrated with the complexity that it introduces to their applications. For example, consider an application that reads a string of the form "path/in/naming/service" from a runtime configuration file. The developers of such an application have to write their own function to convert the string into the CosNaming::Name format. One problem is that it is a waste of time for numerous developers in different organizations around the world to re-invent the wheel in writing such a utility function. Another problem is that each of these developers must choose what hierarchical separator they want and the separator between the id and kind fields of NameComponent. As it turns out, most developers choose to use UNIX-style separators of "/" and ".".

#pragma prefix "" module CosNaming { ... interface NamingContextExt : NamingContext { typedef string StringName; StringName to_string(in Name n) raises(...); Name to_name(in StringName sn) raises(...); Object resolve_str(in StringName sn) raises(...); ... }; };
Figure 4.2: Extract from the NamingContextExt interface

Hindsight is a wonderful thing, and a few years later the OMG decided to simplify the complexity of hierarchical names by defining a new version of the Naming Service. As I will discuss in Section 9.3, IDL does not have a versioning mechanism, so the simplified Naming Service was defined by defining a sub-type that inherits from NamingContext.3 An extract of this new type can be seen in Figure 4.2 (only some of the operations are shown and the raises clauses have been omitted for brevity). The to_string() and to_name() operations convert between the CosNaming::Name and "path/in/naming/service" formats. As an extra convenience, clients can call resolve_str() to resolve (that is, lookup) an IOR from the Naming Service without having to convert "path/in/naming/service" into CosNaming::Name format. However, there is no similar utility operation defined for the bind() or rebind() operations that servers use to advertise an IOR in the Naming Service.

The final area of potential confusion for developers is the list() operation, which is illustrated in Figure 4.1. An out parameter of this operation provides a non-recursive listing of the entries in a naming context. Because the listing is non-recursive, the binding_name field of each Binding should be of type NameComponent. The accidental use of type Name makes some developers mistakenly think that this operation provides a recursive listing.

This section has discussed the imperfections of the Naming Service API. These imperfections can cause confusion for new developers. However, once developers are aware of these imperfections, use of the Naming Service is straightforward. Certainly the imperfections of this API seem minor in comparison to imperfections in the APIs of some other (non-middleware) systems.

4.3  Practical Usage of the Naming Service

The Naming Service defines IDL operations that can be used to create, modify and delete a hierarchy of NamingContexts. However, performing Naming Service maintenance by writing programs that invoke these operations is tedious. Virtually all implementations of the Naming Service provide command-line utilities and/or a GUI “wrapper” around these IDL operations. These command-line utilities and/or GUI programs provide a practical way to perform administration of a Naming Service. Note, however, that such utilities are not part of the CORBA specification. Because of this, the utilities provided will vary from one CORBA product to another.

Once administration issues have been addressed, the only remaining programming aspects associated with the Naming Service are how a server application can bind(), that is, export, an object reference to the Naming Service, and how a client application can resolve(), that is, import, an object reference from the Naming Service. These are straightforward programming tasks.

try { instructions1 = "name_service#path/in/Naming/Service"; instructions2 = "file#/path/to/file.ior"; obj1 = importObjRef(orb, instructions1); exportObjRef(orb, obj2, instructions2); } catch(ImportExportException ex) { cout << ex << endl; }
Figure 4.3: importObjRef() and exportObjRef()

The Importing and Exporting Object References chapter of the CORBA Utilities package [McH] discusses a freely available library (implemented in C++ and Java) that provides utility functions called importObjRef() and exportObjRef(). As their names suggest, these utility functions are for importing and exporting object references. A pseudocode example of their use is illustrated in Figure 4.3. These functions take an instructions parameter that specifies how to import or export an object reference. An instructions parameter that starts with "name_service#" indicates that the Naming Service should be used. The utility functions also support "file#<filename>" and "exec#<command>" for importing or exporting object references through files or by executing an external command. Ideally, an application should not hardcode the value of the instructions parameter, but rather should get it from a command-line option or a configuration file. Doing this provides applications with a lot of flexibility in how they import/export object references. Aside from the flexibility, these utility functions provide a simpler API than that of the Naming Service.

Strictly speaking, the contents of the Naming Service are arranged in a graph that may contain cycles, so comparing the Naming Service to the World Wide Web is more accurate than comparing it to a hierarchical file system. However, in practice, a Naming Service is usually organized in a hierarchical manner.
The "I" in Istring stands for internationalization.
This new version of the Naming Service was defined at the same time as the corbaloc and corbaname URLs (Chapter 12). The combined result was termed the Interoperable Naming Service because corbaloc and corbaname addressed some bootstrapping interoperability issues.

Previous Up Next