So far we have used string_to_object()
and
object_to_string()
to bootstrap the client.
If the system is going to be used in a truly distributed
environment, we cannot count on having a shared file system or on
the user to type the IOR to initialize the client.
CORBA has several location services that can be used for that
purpose. The simplest of them is the CORBA Naming Service.
There are many good tutorials on how to use the Naming Service,
and Henning and Vinoski discuss the issue in detail in their
book.
In this section we will cover very simple uses of the Naming Service, but we will concentrate on how to configure and bootstrap the Naming Service itself! Including TAO's support for the Interoperable Naming Service.
First we modify the server to register the stock factory with the naming service. We need to include the right header:
#include "orbsvcs/CosNamingC.h"
We recall that we activate the stock factory using:
// Activate it to obtain the object reference Quoter::Stock_Factory_var stock_factory = stock_factory_i._this ();
We need to obtain a reference to the Naming Service; this is
done using the resolve_initial_references()
call:
CORBA::Object_var naming_context_object = orb->resolve_initial_references ("NameService"); CosNaming::NamingContext_var naming_context = CosNaming::NamingContext::_narrow (naming_context_object.in ());
Next we initialize the name that we will assign to the objects. The naming service uses a sequence of structures for the name -- think of it as a pathname decomposed into its directories. In this case we will use a simple name. In production environments some better organized hierarchy may be imposed. First create and initialize the sequence:
CosNaming::Name name (1); name.length (1);
Now we initialize the name:
name[0].id = CORBA::string_dup ("Stock_Factory");
Now we are ready to register the object reference in the naming service:
naming_context->bind (name, stock_factory.in ());
Notice that bind()
fails if the name is already in
the naming service. You may want to use rebind()
to
override any values already there.
Now the client can use the Naming Service to locate the object. Instead of relying on the command line, we have to perform the same calls to locate the naming service and initialize the name of the object we want to look up:
CORBA::Object_var naming_context_object = orb->resolve_initial_references ("NameService"); CosNaming::NamingContext_var naming_context = CosNaming::NamingContext::_narrow (naming_context_object.in ()); CosNaming::Name name (1); name.length (1); name[0].id = CORBA::string_dup ("Stock_Factory");
Now we can resolve the name:
CORBA::Object_var factory_object = naming_context->resolve (name); Quoter::Stock_Factory_var factory = Quoter::Stock_Factory::_narrow (factory_object.in ());
And then we can use the object as before.
Complete the changes to the server.cpp
file.
You can use the following files to complete and test your implementation: Quoter.idl, Makefile, Stock_i.h, Stock_i.cpp, Stock_Factory_i.h Stock_Factory_i.cpp. For more fun you can modify the original client.cpp file, too. What about the first argument? Do we need the IOR now?
Compare your solution with client.cpp and server.cpp. They should be very similar.
To test your changes you need to run four programs. First configure TAO's naming service lookup protocol to use a unique port in your LAN. Something based on your user id is a good idea, for example:
$ setenv NameServicePort `expr 10000 + $uid`
Now we can start the Naming Service provided with TAO:
$ $TAO_ROOT/orbsvcs/Naming_Service/tao_cosnaming
and your server:
$ server
and finally the client:
$ client MSFT RHAT RHAT MSFT
So how does TAO find the naming service? Until recently there was no standard way to configure how the Naming Service was bootstrapped. In TAO we decided to use IP multicast to locate the server. The multicast protocol is very simple minded, but works well in small LANs where there are not many naming services running. To avoid problems when multiple naming services run in the same LAN, you must assign a different multicast port to each one, as shown above.
Unfortunately the protocol shown above does not work across
multiple LANs, and it is hard to ensure that there are no
conflicts in the assignment of multicast ports.
TAO supports the Interoperable Naming Service specification
that provides several mechanisms to control the behavior of the
resolve_initial_references()
call.
For example, you can ask the Naming Service to dump its IOR to a
file, as in:
$ $TAO_ROOT/orbsvcs/Naming_Service/tao_cosnaming -o ns.ior
and then use the -ORBInitRef
to that IOR
instead of the multicast protocol:
$ server -ORBInitRef NameService=`cat ns.ior`
or even better use the file:
scheme to read the
file directly:
$ server -ORBInitRef NameService=file://ns.ior
but this still assumes that there is a shared filesystem
between the hosts, or that the user will copy the file across
the network. If we know what host and port the Naming Service
is using to accept IIOP requests, then we can use the
corbaloc:
scheme:
$ server -ORBInitRef NameService=corbaloc:iiop:ace.cs.wustl.edu:12345/NameService
In fact, controlling the host and port of any TAO program,
including the Naming Service, is easy. Just use the
-ORBEndPoint
option:
$ $TAO_ROOT/orbsvcs/Naming_Service/tao_cosnaming -ORBEndPoint iiop://ace.cs.wustl.edu:12345
Of course, this only works if you are running the program in
ace.cs.wustl.edu
and the 12345
port is
free. You can use the magic port number 0
to let
the ORB find a free port. In fact, that is exactly what TAO does
by default.
Finally, you can use multiple -ORBEndPoint
options
to listen on multiple endpoints. This is very useful for
multi-hosted machines.
Try using different approaches to find the Naming Service. Also try to run the server with an invalid IOR for the naming service. What happens if the server and client pick different naming services through their multicast protocol? What happens if they are not configured consistently with respect to their Naming Service?
What happens if the naming service is killed between the object registration and the lookup? By default TAO's Naming Service is not persistent, but it is a matter of using a flag to save its state on a file:
$ $TAO_ROOT/orbsvcs/Naming_Service/tao_cosnaming -f name_service.dat
Notice that this is little use unless your services are persistent too, or can be automatically restarted. That is the role of the Implementation Repository.