New York University

Computer Science Department

Courant Institute of Mathematical Sciences

 

The CosNaming Module

 

Course Title: Application Servers                                                       Course Number: g22.3033-011

Instructor: Jean-Claude Franchitti                                                        Session: 5

 

Traveling in a naming graph

The CosNaming module is the module which implements the CORBA name service. It is used to associate to each object a human readable string which is then used to find the object reference upon need. This is exactly similar to the DNS which allows you to associate simple hierarchised names like “www.what…ever.com” to less usefull IP adresses: 137.194.8.56 .

 

Here, names like "HOME.servers.Panel" are used to register object references. Typically, the server registers the name and clients ask the naming service whether the name was registered or not. If it was registered, clients get the server object reference from the naming service and send requests to the server object.

 

Here is some vocabulary specific to the CORBA naming service: names are bound to objects' references in a given context. Resolving a name is finding the object reference bound to the name within a given context. Contexts are CORBA objects: they may be bound like other objects and are used to create naming graphs.Each naming graph node is a naming context object and leafs are your own objects bindings. An Object name is the compound name made of the node names and the leaf name necessary to describe the path in the naming graph from the root to the object binding. For example, home's naming graph is rather simple. We have: root -> HOME -> servers

 

The Home Panel compound name is : root -> HOME -> servers -> Panel

 

Here is the CosNaming module IDL:

 

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;

  };

  interface NamingContext {

    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);

  };

};

 

I purposefully removed some definitions from this huge interface to make things clearer.

 

We have the binding operations which allow for the creation of the naming graph: bind, rebind, and unbind allow you to create name bindings within a given context (they allow you to create a naming graph leaf), bind_context, rebind_context, new_context and bind_new_context allow you to create naming contexts (they allow you to create the naming graph nodes). Lastly, resolve will help you to get the object reference from the naming graph with the compound name.

 

Here is some server code to bind an object to a name.

 

/* This is some code the Panel could

 * execute upon startup to register

 * against the name service

 */

main ()

{

  CORBA_Object orb;

  CORBA_Environment ev;

  CosNaming_NamingContext root;

  CosNaming_NameComponent name_component[3] = { {"HOME", "subcontext"},

                                                {"Servers", "subcontext"}

                                                {"home_panel", "server"} };

  CosNaming_Name name = {3, 3, name_component, CORBA_FALSE};

  CORBA_Object panel;

 

  CORBA_exception_init (&ev);

  CORBA_ORB_init (&ev);

 

  root = CORBA_ORB_resolve_initial_service (orb,

                                            "NameService",

                                            &ev);

  if (ev->_major != CORBA_NO_EXCEPTION) {

    fprintf (stderr,

             "Error: could not get name service: %s\n",

             CORBA_exception_id(&ev));

    exit (1);

  }

 

  /* here, we have some code to register

   * the server against the ORB and create

   * a valid object reference stored in panel.

   * this is for chapter 4: the POA

   */

 

  CosNaming_NamingContext_bind (root, &name, panel, &ev);

  if (ev->_major != CORBA_NO_EXCEPTION) {

      fprintf (stderr,

               "Error: could register object: %s\n",

               CORBA_exception_id(&ev));

      exit (1);

  }

  CORBA_exception_free (&ev);

  return 0;

}

 

 

Here is some client code to resolve the server name

 

#include <corba.h>

 

int main (int argc, char *argv)

{

  CORBA_Object orb;

  CORBA_Environment ev;

  CosNaming_NamingContext *root;

  CosNaming_NameComponent name_component[3] = { {"HOME", "subcontext"},

                                                {"Servers", "subcontext"}

                                                {"home_panel", "server"} };

  CosNaming_Name name = {3, 3, name_component, CORBA_FALSE};

  CORBA_Object panel;

 

  CORBA_exception_init (&ev);

  CORBA_ORB_init (&ev);

 

  root = CORBA_ORB_resolve_initial_service (orb,

                                            "NameService",

                                            &ev);

  if (ev->_major != CORBA_NO_EXCEPTION) {

    fprintf (stderr,

             "Error: could not get name service: %s\n",

             CORBA_exception_id(&ev));

    exit (1);

  }

 

  panel = CosNaming_NamingContext_resolve (root,

                                           &name,

                                           &ev);

  if (ev->_major != CORBA_NO_EXCEPTION) {

      fprintf (stderr,

               "Error: could resolve object: %s\n",

               CORBA_exception_id(&ev));

      exit (1);

  }

 

  /* there, the panel variable holds a CORBA_Object to the home panel

   * it is now possible to call some of the panel methods defined in

   * core/idl/home-panel.idl

   */

 

  CORBA_free (root);

  CORBA_exception_free (&ev);

 

  return 0;

}

 

The CosNaming_NameComponent and CosNaming_Name structures are straight C mappings of the corresponding IDL definitions in the CosNaming module.

 

Please, note that if the client does not know exactly the server name, he may use the list method to get a list of a context bindings.

Initialization

One problem still hasn't been resolved: in these code examples, one implicitely admits that we have had before beginning to use the NameService a NamingContext object. The problem is how to get one ? The only object we know we have access to is the ORB because there is a special initialisation function CORBA_ORB_init.

 

In fact, it happens that the ORB interface has a special method to get an initial refrence to a naming context and use its methods to resolve or bind names.

 

Here is the IDL:

 

module CORBA {

  interface ORB {

    typedef string ObjectId;

    typedef sequence <ObjectId> ObjectIdList;

    ObjectIdList list_initial_services ();

   

    Exception InvalidName {};

    Object resolve_initial_reference (in ObjectId identifier)

           raises (InvalidName);

  };

};

 

The ORBit ORB has two interesting methods: list_initial_services and resolve_initial_reference. The first one will return a list of the available services this ORB may resolve. As of CORBA 2.2, the folowing are standardized: "RootPoa", "POACurrent", "InterfaceRepository", "NameService", "TradingService", "SecurityCurrent" and "TransactionCurrent". This means that a call to a 2.2 ORB should return a list of these strings. As an example, in “ORBit” the following code displays on screen the list of available services:

 

#include <corba.h>

 

int main (int argc, char **argv)

{

  CORBA_ORB orb;

  CORBA_Environment ev;

  CORBA_sequence_ObjectId *seq;

  CORBA_unsigned_long i;

 

  CORBA_exception_init (&ev);

  orb = CORBA_ORB_init (&ev);

 

  seq = CORBA_ORB_list_initial_services (orb, &ev);

 

  for (i=0; i<seq->_lenght ;i++) {

    fprintf (stdout, "%s\n" ,(seq->_buffer)[i]);

  }

 

  return 0;

}

 

The resolve_initial_service method will return an object reference for the string passed as a parameter. This is how you get the object reference of the naming service. Before calling CORBA_ORB_resolve_initial_service (orb, "NameService", &ev), you had no access to any object (except if you used ior string but this required some hacking as you saw earlier). Now, you have an object reference to a naming context and may register youself if you are a server or get a server object reference if you are a client using the object name

 

Note: The only problem with this code is that it does not work. ORBit has a NameService which may be enabled by launching the corresponding "orbit-name-server" but this name server cannot be resolved with this CORBA_ORB_init call. One needs to use the name-server IOR string which is displayed upon the name server launch. The recommended method to use it is to launch it with: "orbit-name-server >/tmp/name-service-ior &". This will store the IOR string in /tmp/name-service-ior which can then be read with code similar to the one we studied a little earlier. This problem could be solved elegantly by providing a get_name_service api function.