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.