Java IDL and RMI-IIOP: Naming Services

# Naming Service

Topics in this section include:

- COS Naming Service: an Overview
- Using the Naming Service

## COS Naming Service: an Overview

The CORBA COS (Common Object Services) Naming Service provides a tree-like directory for object references much like a filesystem provides a directory structure for files. The Naming Service provided with Java IDL is an implementation of the COS Naming Service specification. The following overview is taken from that document.

> A name-to-object association is called a name binding. A name binding is always defined relative to a naming context. A naming context is an object that contains a set of name bindings in which each name is unique. Different names can be bound to an object in the same or different contexts at the same time.

> To resolve a name is to determine the object associated with the name in a given context. To bind a name is to create a name binding in a given context. A name is always resolved relative to a context - there are no absolute names.

> Because a context is like any other object, it can also be bound to a name in a naming context. Binding contexts in other contexts creates a naming graph - a directed graph with nodes and labeled edges where the nodes are contexts. A naming graph allows more complex names to reference an object. Given a context in a naming graph, a sequence of names can reference an object. This sequence of names (called a compound name) defines a path in the naming graph to navigate the resolution process.

The following figure shows an example of a naming graph. A sample program that illustrates how to add names to the namespace uses this same model.

For an application to use the COS Naming Service, its ORB must know the port of a host running a naming service or have access to a stringified initial naming context for that naming service. The naming service can either be the Java IDL naming service or another COS-compliant naming service.

Prior to running a client or a server, you will start ORBD. ORBD includes a persistent Naming Service and a transient Naming Service, both of which are an implementation of the COS Naming Service.

- The Persistent Naming Service provides persistence for naming contexts. This means that this information is persistent across service shutdowns and startups, and is recoverable in the event of a service failure. If ORBD is restarted, the Persistent Naming Service will restore the naming context graph, so that the binding of all clients' and servers' names remains intact (persistent).

- For backward compatibility, `tnameserv`, a Transient Naming Service shipped with older versions of the JDK, is also included in J2SE v.1.4. A transient naming service retains naming contexts as long as it is running. If there is a service interruption, the naming context graph is lost.

Both client and server should agree on which root naming context to use. The `orb.resolve_initial_references(String name_of_service)` method is used to obtain the root naming context. If you get a handle on a Naming Service by providing `"NameService"` as the name_of_service, you will get a persistent naming service, meaning that the naming context graph will be restored after a service failure. If you get the handle using `"TNameService"`, you will get a transient naming service, meaning that you will need to re-obtain the root naming context using `orb.resolve_initial_references(String name_of_service)` if there is a service interruption.

For example,

          // get the root naming context
          org.omg.CORBA.Object objRef =
              orb.resolve_initial_references("NameService");
          NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);

The string "NameService" is defined for all CORBA ORBs. When you pass in this string, the ORB returns a naming context object that is an object reference for:

- The persistent name service if you are using the Naming Service that is part of ORBD.
- The transient name service if you are using `tnameserv`.

To specify that you want to use the transient naming service with ORBD, pass in the string "TNameService". The string "TNameService" is a proprietary name. When you pass in this string, the ORB returns a naming context object that is an object reference for ORBD's transient name service.

As with all CORBA object references, `objRef` is a generic CORBA object. To use it as a `NamingContextExt` object, you must narrow it to its proper type.

`NamingContextExtHelper` is an `idlj`-generated helper class, similar in function to `HelloHelper`. The `ncRef` object is now an `org.omg.CosNaming.NamingContextExt` and you can use it to access the naming service and register the server.

`NamingContextExt` and `NamingContextExtHelper` are new to this release of J2SE. `NamingContextExt` is the extension of `NamingContext`. It contains a set of name bindings in which each name is unique and is part of the Interoperable Naming Service. Different names can be bound to an object in the same or different contexts at the same time. Using `NamingContextExt`, you can use URL-based names to bind and resolve. `NamingContextExtHelper` provides additional helper methods like `narrow()` that are type-specific but don't deal with business logic.

### Interoperable Naming Service

The Interoperable Naming Service (INS) is a URL-based naming system on top of the CORBA Naming Service, as well as a common bootstrap mechanism that lets applications share a common initial naming context.

The Interoperable Naming Service (INS) provides the following features:

- Capability to resolve using stringified names (e.g., a/b.c/d)
- URLs for CORBA object references (corbaloc: and corbaname: formats)
- Standard APIs in `NamingContextExt` for converting between CosNames, URLs, and Strings
- ORB arguments for bootstrapping (`ORBInitRef` and `ORBDefaultInitRef`)

An example application that demonstrates how to use the INS can be found at Interoperable Naming Service Example.

The following diagram shows how INS fits into ORBD:

An object reference contains at least three pieces of information: an address, the name of the POA that created an object reference, and an Object ID.

Using INS, you can provide a URL to access the CORBA object, which is more readable than a stringified IOR. The following stringified object reference formats are allowed:

- Interoperable Object References (IOR)

  An IOR is an object reference that is understood by ORBs that can interoperate using the OMG-defined protocols GIOP and IIOP. A client can obtain an object reference using `orb.object_to_string(objRef)`, as shown in the Browsing the Namespace example, or as a result of an invocation on another object reference.

  Note: If an IOR contains multiple profiles, the J2SE v.1.4 ORB always uses the first one.

- Human-Readable URL Formats for CORBA Object References

  - corbaloc:

    The `corbaloc:` format is useful for CORBA client programs, and is typically used to resolve the reference using the GIOP `LocateRequest` or `Request` message. For example, a `corbaloc:` object reference might look like this:

         	corbaloc:iiop:1.2@MyBank.com:2050/TraderService

    This example show how to get an object reference for `TraderService` from host `myBank.com` on port `2050`.

  - corbaname:

    The `corbaname:` format provides a mechanism for a client to bootstrap directly, and is typically used to resolve the stringified name from the root naming context. For example, a `corbaname:` object reference might look like this:

         	corbaname::myBank.com:2050#Personal/schedule

    where `myBank.com` is the host, `2050` is the port. The portion of the reference up to the hash mark (`corbaname::myBank.com:2050` ) is the URL that returns the root naming context. This example provides the URL to use to: a) locate the Naming Service, and, b) resolve the name `Personal/schedule` from the Naming Service.

#### Bootstrap Options for the ORB

INS provides ORB options for bootstrapping. To bootstrap a CORBA system, you must give it an object reference. The ORB can be configured to return the handle of a customized CORBA service from `resolve_initial_references()` using either `ORBInitRef` and/or `ORBDefaultInitRef`. For example,

    -ORBInitRef TraderService=corbaloc::myBank.com:2050/TraderService
    -ORBDefaultInitRef corbaloc:iiop:1.2:myBank.com:2050

The order of resolution when these options are used is as follows:

1. Objects registered with `register_initial_references`
2. `-ORBInitRef`
3. `-ORBDefaultInitRef`
4. Proprietary Bootstrap (Sun ORBs only)

For more information about INS, refer to the OMG specification at (ptc/00-08-07).

## Using the Naming Service

To use the Naming Service, you must first write the server and client code that finds and/or creates the namespace and/or the objects in the namespace. Before running the client and server, you must start the Naming Service and tell the client and server where to find it. The following steps loosely suggest what happens when the client and server attempt to access the Naming Service:

- The server invokes the `bind` or `rebind` method to associate a logical name with an object reference.
- The Naming Service adds this object reference/name binding to its namespace database.
- A client application invokes the `resolve` method to obtain an object reference with this name.
- The client uses an object reference to invoke methods on the target object.

The following topics are covered in this section:

- Sample Client: Adding Objects to the Namespace
- Sample Client: Resolving Objects from the Namespace
- Sample Client: Browsing the Namespace
- Starting the Naming Service
- Stopping the Naming Service

### Sample Client: Adding Objects to the Namespace

The following sample program illustrates how to add names to the namespace. It is a self-contained Naming Service client that creates the following simple tree. Naming contexts are in italics and object references are in `normal` font.

In this example, plans is an object reference and Personal is a naming context that contains two object references: calendar and schedule.

1. Create the `NameClient.java` file and import the proper libraries:

       import java.util.Properties;
       import org.omg.CORBA.*;
       import org.omg.CosNaming.*;

       public class NameClient
       {
          public static void main(String args[])
          {
             try {

2. Set Port and Host properties.

   In the section, Starting the Naming Service, the name server is started on port 1050 and host localhost. The following code ensures that the client program is aware of this port number and host name.

               Properties props = new Properties();
               props.put("org.omg.CORBA.ORBInitialPort", "1050");
               props.put("org.omg.CORBA.ORBInitialHost", "localhost");
               ORB orb = ORB.init(args, props);

3. Obtain the initial naming context.

   The following code obtains the initial naming context and assigns it to ctx. The second line copies ctx into a dummy object reference objref that we'll attach to various names and add into the namespace.

               NamingContextExt ctx =
                 NamingContextExtHelper.narrow(orb.resolve_initial_references(
                   "NameService"));
               org.omg.CORBA.Object objref = ctx;

4. Bind the name "plans" to the object reference.

   This code binds the name "plans" to our dummy object reference. The object reference, "plans", is then added under the initial naming context using `rebind`. The `rebind` method allows us to run this program over and over again without getting the exceptions we'd get from using `bind`.

               NameComponent name1[] = ctx.to_name("plans");
               ctx.rebind(name1, objref);
               System.out.println("plans rebind successful!");

5. Create a new naming context named "Personal".

   This code creates a new naming context called "Personal". The resulting object reference, ctx2, is bound to the name and added under the initial naming context.

               NameComponent name2[] = ctx.to_name("Personal");
               NamingContextExt ctx2 = ctx.bind_new_context(name2);
               System.out.println("New naming context, Personal, added!");

6. Bind "schedule" and "calendar" to a dummy object reference. To bind a name is to create a name binding in a given context. A name is always resolved relative to a context - there are no absolute names.

   This code binds the dummy object reference using the names "schedule" and "calendar" under the "Personal" naming context (ctx2).

               NameComponent name3[] = ctx.to_name("schedule");
               ctx2.rebind(name3, objref);
               System.out.println("schedule rebind successful!");

               NameComponent name4[] = ctx.to_name("calendar");
               ctx2.rebind(name4, objref);
               System.out.println("calendar rebind successful!");

           } catch (Exception e) {
               e.printStackTrace(System.err);
           }
         }
       }

7. Save NameClient.java, and compile the file as follows:

            javac NameClient.java

   Correct any syntax errors before proceeding.

8. Run the Object Request Broker Daemon as shown in Starting the Naming Service.

9. Run `NameClient`, as follows:

            java NameClient -ORBInitialPort 1050

The output in the terminal window looks like this:

We now have a namespace that to the Naming Service looks like the above diagram.

### Sample Client: Resolving Objects from the Namespace

The following sample program illustrates how to resolve names from the namespace. To resolve a name is to determine the object associated with the name in a given context. When using the persistent Naming Service, you do not need to re-resolve if the Naming Service goes down. If you use a transient Naming Service, you do need to re-resolve in the Naming Service goes down.

In this example, plans is an object reference and Personal is a naming context that contains two object references: calendar and schedule.

1. Create the `NameClientResolve.java` file and import the proper libraries:

       import java.util.Properties;
       import org.omg.CORBA.*;
       import org.omg.CosNaming.*;

       public class NameClientResolve
       {
          public static void main(String args[])
          {
             try {

2. Set Port and Host properties.

   In the section, Starting the Naming Service, the name server is started on port 1050 and host localhost. The following code ensures that the client program is aware of this port number and host name.

               Properties props = new Properties();
               props.put("org.omg.CORBA.ORBInitialPort", "1050");
               props.put("org.omg.CORBA.ORBInitialHost", "localhost");
               ORB orb = ORB.init(args, props);

3. Obtain the initial naming context.

   The following code obtains the initial naming context and assigns it to nc.

               NamingContextExt nc =
                 NamingContextExtHelper.narrow(orb.resolve_initial_references(
                   "NameService"));

4. Resolve each namespace.

   The following code resolves each namespace.

          org.omg.CORBA.Object sched = nc.resolve_str("Personal/schedule");
               org.omg.CORBA.Object cal = nc.resolve_str("Personal/calendar");
               org.omg.CORBA.Object plan = nc.resolve_str("plans");

             //finish the try-catch block
             } catch (Exception e) {
               e.printStackTrace(System.err);
               }
       }

5. Save NameClientResolve.java, and compile the file as follows:

            javac NameClientResolve.java

   Correct any syntax errors before proceeding.

6. Make sure the Object Request Broker Daemon is running and the client application illustrated in Sample Client: Adding Objects to the Namespace has been run.

7. Run `NameClientResolve`, as follows:

            java NameClientResolve -ORBInitialPort 1050

There is no output to the terminal window when you run this client application. If you want verification that the object references have been resolved, you could add code such as the following for testing purposes:

    	if (sched == null){
    	  System.out.println("Schedule is null");
    	}

    	if (cal == null){
    	  System.out.println("Calendar is null");
    	}

    	if (plan == null){
    	  System.out.println("Plans is null");
    	}

### Sample Client: Browsing the Namespace

The following sample program illustrates how to browse the namespace.

1. Create the `NameClientList.java` file and import the proper libraries:

       import java.util.Properties;
       import org.omg.CORBA.*;
       import org.omg.CosNaming.*;

       public class NameClientList
       {
          public static void main(String args[])
          {
             try {

2. In the section, Starting the Naming Service, the nameserver is started on port 1050 and host localhost. The following code ensures that the client program is aware of this port number and host name.

               Properties props = new Properties();
               props.put("org.omg.CORBA.ORBInitialPort", "1050");
               props.put("org.omg.CORBA.ORBInitialHost", "localhost");
               ORB orb = ORB.init(args, props);

3. Obtain the initial naming context.

               NamingContextExt nc =
                 NamingContextExtHelper.narrow(orb.resolve_initial_references(
                   "NameService"));

4. List all bindings in the naming context.

   The `list` method lists the bindings in the naming context. In this case, up to 1000 bindings from the initial naming context will be returned in the `BindingListHolder`; any remaining bindings are returned in the `BindingIteratorHolder`.

               BindingListHolder bl = new BindingListHolder();
               BindingIteratorHolder blIt= new BindingIteratorHolder();
               nc.list(1000, bl, blIt);

5. Get the array of bindings.

   This code gets the array of bindings out of the returned BindingListHolder.

               Binding bindings[] = bl.value;

6. This code loops through the bindings and prints the names out.

               for (int i=0; i < bindings.length; i++) {

                   int lastIx = bindings[i].binding_name.length-1;

                   // check to see if this is a naming context
                   if (bindings[i].binding_type == BindingType.ncontext) {
                     System.out.println( "Context: " +
                       bindings[i].binding_name[lastIx].id);
                   } else {
                       System.out.println("Object: " +
                         bindings[i].binding_name[lastIx].id);
                   }
               }

              } catch (Exception e) {
               e.printStackTrace(System.err);
              }
          }
       }

7. Save NameClientList.java, and compile the file as follows:

            javac NameClientList.java

   Correct any syntax errors before proceeding.

8. Make sure the Object Request Broker Daemon is running, the client application illustrated in Sample Client: Adding Objects to the Namespace has been run, and the client application illustrated in Sample Client: Resolving Objects from the Namespace has been run.

9. Run `NameClientList`, as follows:

            java NameClientList -ORBInitialPort 1050

The output in the terminal window looks like this:

### Starting the Naming Service

In all of the tutorials we use the Object Request Broker Daemon, `orbd`, which includes both a Persistent and a Transient Naming Service, and is available with every download of J2SE 1.4 and higher.

For a caller (client, peer, or client application) to be able to invoke a method on a remote object, that caller must first obtain a reference to the remote object.

Once a remote object is registered on the server, callers can look up the object by name, obtain a remote object reference, and then remotely invoke methods on the object.

To learn how to start the Naming Service, see the topic Starting the Naming Service in the ORBD documentation.

### Stopping the Naming Service

To stop the naming service, use the relevant operating system command, such as `kill` on Solaris, or `Ctrl+C` in the DOS window in which `orbd` is running. Note that names registered with the naming service may disappear when the service is terminated if the naming service is transient. The Java IDL naming service will run until it is explicitly stopped.

## Naming Service FAQ

### How do I connect to a 3rd-party Naming Service from Sun's ORB?

> The recommended way is to use the Inter-Operable Naming Service (INS), if this option is supported by the 3rd-party Naming Service.

> To use the Sun ORB with another vendor's Naming Service,

> 1. Start the 3rd-party name server on Host and Port.

> 2. Pass the following argument to `ORB.init()`:

>                -ORBInitRef NameService=corbaloc:iiop:1.2@:/NameService

> When you do `orb.resolve_initial_references( "NameService" )`, you should be able to connect to 3rd-party Name Service. If you are still not able to connect, try these troubleshooting hints:

> - Verify that the 3rd-party Name Service supports INS.
> - Verify that the host and port information is accurate.
> - Verify that the 3rd-party Name Service has been started successfully.
> - Verify that the 3rd-party Name Service supports GIOP 1.2. If not, refer to the Name Server's documentation for the correct the GIOP version, and modify the `corbaloc:` URL accordingly.
> - Determine if the 3rd-party Name Service has a different object key it uses to contact `NameService`. If so, refer to the Name Server's documentation.

Java IDL Home