Server Example
The main interaction a server has with the naming service is to create object bindings to advertise objects to clients. The operations most often used are rebind() or bind(), to create object bindings, and bind_new_context(), to create context bindings that hold the object bindings.
However, the operations provided directly by the naming service interface are fairly primitive. In most real-life projects, you will find it helpful to build some kind of utility or wrapper around the naming service. In the examples that follow, a class NameUtil is defined that provides a more convenient way of accessing the naming service.
One of the things missing from the naming IDL is a way to create multiple components in a single step. For example, if you want to create a naming context named A/B/C/D, and neither A, B, C, nor D exists yet, it will take at least four explicit invocations of bind_new_context() to create the naming context. To simplify this process, our name utility defines the following operations:
NameUtility::createContextPath()Creates a multicomponent naming context. For example, if you want to create the naming context A/B/C/D, it fills in any context bindings missing between A and D.
NameUtility::bindObjectPath()Creates a multicomponent object binding. For example, if you want to create the object binding A/B/C/D/MyObj, it fills in any context bindings missing between A and MyObj.
The code for these two methods is given in the following sections.
Name Utility - createContextPath()
The method createContextPath() is used to create a name component, filling in any missing components along the way. The implementation of the method in C++ and Java is given in Listing 3 and Listing 4.
Listing 3: C++ Implementation of createContextPath()
// C++ //---------------------------------------- // method: 'createContextPath()' // // purpose: For each 'NameComponent' in 'name', // create a corresponding 'NamingContext'. //---------------------------------------- void NameUtil::createContextPath( const CosNaming::NamingContext_ptr nc, const CosNaming::Name& name ) { int isNotFound = 0; CORBA::ULong lengthMissing = 0; CosNaming::NamingContext_var tmpCtxVar; try { tmpCtxVar = nc->bind_new_context(name); } catch (CosNaming::NamingContext::NotFound& nf) { isNotFound = 1; lengthMissing = nf.rest_of_name.length(); } if (lengthMissing==name.length() ) { cerr << "This cannot happen!" << endl; } if (isNotFound) { for (CORBA::ULong l=name.length()-lengthMissing; l <= name.length(); l++) { CosNaming::Name tmpName = name; tmpName.length(l); tmpCtxVar = nc->bind_new_context(tmpName); } } }
Listing 4: Java Implementation of createContextPath()
// Java package Pure.Util; import org.omg.CORBA.*; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.*; import org.omg.PortableServer.POAManagerPackage.*; public class NameUtil { //---------------------------------------- // method: 'createContextPath()' // // purpose: For each 'NameComponent' in 'name', // create a corresponding 'NamingContext'. //---------------------------------------- public static void createContextPath( NamingContext nc, NameComponent[] name ) throws org.omg.CORBA.UserException { boolean isNotFound = false; int lengthMissing = 0; NamingContext tmpCtx; try { tmpCtx = nc.bind_new_context(name); } catch (NotFound nf) { isNotFound = true; lengthMissing = nf.rest_of_name.length; } if (isNotFound && lengthMissing==name.length ) { System.err.println("This cannot happen!"); return; } if (isNotFound) { for (int len = name.length-lengthMissing; len <= name.length; len++) { NameComponent[] tmpName = new NameComponent[len]; for (int i=0; i < len; i++) { tmpName[i] = name[i]; } tmpCtx = nc.bind_new_context(tmpName); } } } ... }
The implementation makes interesting use of the NotFound exception. The NotFound exception is declared in IDL as follows:
// IDL module CosNaming { ... interface NamingContext { ... enum NotFoundReason { missing_node, not_context, not_object }; exception NotFound { NotFoundReason why; Name rest_of_name; }; ... }; };
Consider, for example, what happens if you want to create the naming context A/B/C/D but only A exists initially. The createContextPath() method performs the following steps:
A call to bind_new_context() is made. This only works if the naming context A/B/C already exists. Since B and C are missing, the NotFound exception is thrown.
The NotFound exception is caught and the length of the missing part of the name is extracted. Since two components, B and C, are missing between A and D, the number of missing components is 2. The value of rest_of_name is B/C.
A for loop creates all of the components needed to complete the pathA/B, A/B/C, and A/B/C/D.
The NotFound exception allows you to avoid using trial and error to identify the components that need to be created. The approach used here minimizes the number of remote calls that must be made.
Name Utility - bindObjectPath()
The method bindObjectPath() is used to create an object binding, filling in any missing components along the way. The implementations of the method in C++ and Java are given in Listing 5 and Listing 6.
Listing 5: C++ Implementation of bindObjectPath()
// C++ //---------------------------------------- // method: 'bindObjectPath()' // // purpose: For the first [0, length-2] NameComponents of // 'name', create a corresponding 'NamingContext'. // For the length-1 NameComponent of 'name', bind it // to the object reference 'obj'. //---------------------------------------- void NameUtil::bindObjectPath( const CosNaming::NamingContext_ptr nc, const CosNaming::Name& name, const CORBA::Object_ptr obj ) { try { nc->rebind(name, obj); } catch (CosNaming::NamingContext::NotFound& ) { CosNaming::Name tmpName = name; tmpName.length(tmpName.length()-1); createContextPath(nc, tmpName); nc->bind(name, obj); } }
Listing 6: Java Implementation of bindObjectPath()
// Java package Pure.Util; import org.omg.CORBA.*; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.*; import org.omg.PortableServer.POAManagerPackage.*; public class NameUtil { //---------------------------------------- // method: 'bindObjectPath()' // // purpose: For the first [0, length-2] NameComponents of // 'name', create a corresponding 'NamingContext'. // For the length-1 NameComponent of 'name', bind it // to the object reference 'obj'. //---------------------------------------- public static void bindObjectPath( NamingContext nc, NameComponent[] name, org.omg.CORBA.Object obj ) throws org.omg.CORBA.UserException { try { nc.rebind(name, obj); } catch (NotFound nf) { NameComponent[] tmpName = new NameComponent[name.length-1]; for (int i=0; i < name.length-1; i++) { tmpName[i] = name[i]; } createContextPath(nc, tmpName); nc.bind(name, obj); } } }
This utility method delegates most of the work to the createContextPath() method. Consider, for example, that you are creating an object binding called A/B/C/D/MyObj. If the invocation of rebind() gives rise to a NotFound exception, a call to createContextPath() is used to complete the path A/B/C/D before invoking bind() to create the object binding A/B/C/D/MyObj.
Server Mainline
Consider a server that instantiates a single StockExchange object and publishes it to the naming service. For this example, the functionality of the object is not of interest, so a trivial placeholder can be used for the StockExchange interface:
// IDL interface StockExchange { };
Assuming that the interface is implemented by a servant class called StockExchange_i (not shown), the server mainline is given by Listing 7 and Listing 8.
Listing 7: C++ Server Binding a Name
// C++ int main(int argc, char* argv[]) { ... //------------------------------------------------------------------ // The usual initialization boilerplate comes here (not shown). // The following variables are defined by the initialization code: // // 'orbV' - a pointer to the ORB object // // 'poaV' - a pointer to the root POA object // // 'namingContextExtV' - a pointer to the root naming context //------------------------------------------------------------------ StockExchange_i myStockServant; StockExchange_var myStockV = myStockServant._this(); try { nameV = rootContextExtV->to_name( "London.region/Main.failover/StockExchange" ); NameUtil::bindObjectPath( rootContextExtV.in(), nameV.in(), myStockV.in() ); } catch (CORBA::SystemException& se) { cerr << se << endl; return 1; } catch (CORBA::UserException& ue) { cerr << ue << endl; return 1; } try { cout << "Activating the POA manager." << endl; PortableServer::POAManager_var poa_manager= poaV->the_POAManager(); poa_manager->activate(); cout << "Invoking ORB::run()." << endl; orbV->run(); } catch (CORBA::SystemException& se) { cerr << "ORB::run() failed: " << se << endl; return 1; } //Cleanup orbV->destroy(); return 0; }
Listing 8: Java Server Binding a Name
// Java package Pure.NamesDemo; import Pure.Util.*; import org.omg.CORBA.*; import org.omg.CosNaming.*; import org.omg.CosNaming. NamingContextPackage.*; import org.omg.PortableServer.POAManagerPackage.*; public class Server { ... //------------------------------------------------------------------ // The usual initialization boilerplate comes here (not shown). // The following variables are defined by the initialization code: // // 'm_orb' - a reference to the ORB object // // 'poa' - a reference to the root POA object // // 'namingContextExt' - a reference to the root naming context //------------------------------------------------------------------ // // Instantiate a 'StockExchange' object // StockExchange_i myStockServant = new StockExchange_i(); StockExchange myStock = myStockServant._this(m_orb); try { name = rootContextExt.to_name( "London.region/Main.failover/StockExchange" ); NameUtil.bindObjectPath(rootContextExt, name, myStock ); } catch (org.omg.CORBA.SystemException ex) { System.err.println(ex); System.exit(1); } catch (org.omg.CORBA.UserException ux) { System.err.println(ux); System.exit(1); } try { System.out.println("Activating the POA manager."); org.omg.PortableServer.POAManager poa_manager = poa.the_POAManager(); poa_manager.activate(); System.out.println("Invoking ORB::run()."); m_orb.run(); } catch (org.omg.CORBA.SystemException ex) { System.err.println(ex); System.exit(1); } catch (org.omg.CORBA.UserException ux) { System.err.println(ux); System.exit(1); } } }
An object reference for the StockExchange object is obtained by invoking _this() on the servant, which simultaneously activates the object. A stringified name is converted to a raw name using to_name(), and the object binding is then created with the help of the bindObjectPath() utility method.