ACE+TAO Opensource Programming Notes/Create a client

Discussion

edit

So, unlike the server, the client doesn't involve implementing any code generated by the IDL. In the client, we simply instantiate a copy of the factory (using as an address the IOR string we generated with the server) and call its functions. This is all it takes for a basic client.

In the following code, the first argument to the program gets used as the address argument to TAO's orb to find our server. We are using the string generated earlier much like someone would use an IP address/port combination to find a host and application on the internet. While we will discuss it later, this analogy is somewhat apt because, on the internet, we usually prefer to use host names (using DNS) and well known services (ports) to access our services. In CORBA land, the same is true, and we will be discussing that later.

After acquiring the factory object from the orb, we then downcast the generic object to our My_Factory_var object as generated by the IDL. Note that we aren't downcasting it to "My_Factory", but rather "My_Factory_var". TAO, and perhaps CORBA seem to have adopted a standard of using XXX (as defined in your IDL) as the class you use to manipulate the ORB, and XXX_var (as generated by the IDL) as the repository for your object, as generated by XXX.

Now that you have generated your application specific factory object from the generic one received from the ORB, you may proceed to use these two objects as you would any normal C++ object. Just remember to keep in mind the type of data you are getting back from your queries, and or what type of data you are sending. Suffice it to say that inattention to these details will cause memory leaks.

Finally, destroy the ORB. While this is quite a simple application, and technically the destructor isn't needed, its still a good idea to get in the practice as leaving these objects hanging will cause all sorts of problems with distributed programs.

main.cpp

edit
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <iostream>
#include <cstdlib>
#include "ace_serviceI.h"
#include "ace_serviceC.h"

using namespace std;
using namespace CORBA;

int main(int argc, char *argv[])
{
    // initialize the ORB
      ORB_var orb = ORB_init (argc, argv, "whatever");

    // There must be at least two arguments, the first is the factory
    // name, the rest are the names of the stock symbols we want to
    // get quotes for.
      if (argc < 3) {
	cerr << "Usage: " << argv[0]
	    << " Factory_IOR symbol symbol..." << endl;
	return 1;
      }

    // Bring in the IOR
      Object_var factory_object =  orb->string_to_object (argv[1]);

    // Now downcast the object reference 
      My_Factory_var factory =
	  My_Factory::_narrow (factory_object.in ());

    // Now get the full name and price of the other arguments:
      for (int i = 2; i != argc; ++i) {
        // Get the stock object
	  Widget_var widget =
	      factory->get_widget (argv[i]);

        // Get its name, put it on a _var so it is automatically
        // released!
	  String_var full_name = widget->full_name ();

        // Now get the price
	  Double price = widget->price ();

	  cout << "The price of a widget in \""
	      << full_name.in () << "\" is $"
	      << price << endl;
      }

    // Destroy the ORB
      orb->destroy ();
  return EXIT_SUCCESS;
}

ace_service.idl

edit
// Forward declare
interface Widget;

interface My_Factory
{
    // = TITLE
    //   A factory class for the widget interfaces
  //
    // = DESCRIPTION
    //   Return the Widget interfaces based on their names
  //
  Widget get_widget (in string widget_name);
};

interface Widget
{
    // = TITLE
    //   A simple interface to query the name and price of a widget
  //
    // = DESCRIPTION
    //   Return the price and name of a single widget
  //

  readonly attribute string full_name;
    // Get the name.

  double price ();
    // Get the price

};