%% -*- mode: LaTeX -*-
%%
%% Copyright (c) 1997, 1998, 1999 The University of Utah and
%% the Computer Systems Laboratory at the University of Utah (CSL).
%%
%% This file is part of Flick, the Flexible IDL Compiler Kit.
%%
%% Flick is free software; you can redistribute it and/or modify it under the
%% terms of the GNU General Public License as published by the Free Software
%% Foundation; either version 2 of the License, or (at your option) any later
%% version.
%%
%% Flick is distributed in the hope that it will be useful, but WITHOUT ANY
%% WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
%% FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
%% details.
%%
%% You should have received a copy of the GNU General Public License along with
%% Flick; see the file COPYING.  If not, write to the Free Software Foundation,
%% 59 Temple Place #330, Boston, MA 02111, USA.
%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

The source code for the CORBA phonebook application is contained in the
\filename{test/examples/phone/corba} directory of the Flick source tree.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Interface Definition}
\label{subsec:CORBA:Interface Definition}

The CORBA IDL specification of our phonebook interface is straightforward:

\begin{verbatim}
   module data {
       typedef string<200> name;
       typedef string<20>  phone;

       struct entry { name n; phone p; };

       exception duplicate { phone p; };
       exception notfound  {};

       interface phonebook {
           void  add(in entry e)   raises (duplicate);
           void  remove(in name n) raises (notfound);
           phone find(in name n)   raises (notfound);
       };
   };
\end{verbatim}

Assuming that this interface is contained in a file \filename{phone.idl}, the
following commands will compile the phonebook specification into client stubs
and a server skeleton:\footnote{The actual commands issued by the
\filename{Makefile} are somewhat more complicated because they do not assume
that you have installed Flick on your system.  Read the \filename{Makefile} for
details.}

\begin{verbatim}
   flick-fe-newcorba phone.idl

   flick-c-pfe-corba -c -o phone-client.prc phone.aoi
   flick-c-pbe-iiop phone-client.prc
   # Final outputs: `phone-client.c' and `phone-client.h'.

   flick-c-pfe-corba -s -o phone-server.prc phone.aoi
   flick-c-pbe-iiop phone-server.prc
   # Final outputs: `phone-server.c' and `phone-server.h'.
\end{verbatim}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Server Functions}
\label{subsec:CORBA:Server Functions}

For the server, Flick will create a \cfunction{main} function (found in
\filename{phone-server.c}).  To complete the server you must:

\begin{itemize}
  \item define the data structures that the server will need in order to manage
  its objects;

  \item write a \cfunction{register_objects} function that will instantiate the
  server's objects (as described in Section~\ref{subsec:Creating Object
  Implementations}); and

  \item write functions to implement the operations listed in the IDL file.
\end{itemize}

Our simple server will use a linked list to represent its collection of phone
book objects.  Each node in that list will be a `\ctype{struct impl_node_t}'
and will represent a single phonebook:

\begin{verbatim}
   typedef struct impl_node_t *impl_node;

   struct impl_node_t {
       CORBA_ReferenceData id;     /* The search key for this node. */
       data_phonebook obj;         /* CORBA Object ref for this.    */

       data_entry **pb;            /* The array of ptrs to entries. */
       int pb_elems;               /* # of entries in `pb'.         */
       int pb_size;                /* The size of the `pb' array.   */

       impl_node next;             /* Ptr to the next list element. */
   };

   /* `pb_impl_list' is the list of phonebook implementations. */
   impl_node pb_impl_list = 0;
\end{verbatim}

The \ctype{CORBA_ReferenceData} slot of each node will allow us to find the
data for a phonebook, given its CORBA object reference.\footnote{This example
uses a linked list to represent the server's set of phonebooks, but a more
sophisticated application would use a hash table, with keys generated by the
\cfunction{CORBA_Object_hash} function.}  The other slots should be obvious,
although you may be wondering where \ctype{data_entry} is defined.  It is
defined in the file \filename{phone-server.h}, which is created for you by
Flick.  The \ctype{data_entry} structure type is automatically generated from
the the \idl{entry} structure declaration in the source IDL file.

The next step is to write \cfunction{register_objects}, which will be called
from the Flick-generated \cfunction{main} function so that the server can
instantiate its objects and register them with the Flick runtime (the ORB).
The code for this function is shown below and is contained in the
\filename{phone-workfuncs.c} file in Flick's CORBA phonebook source directory.
This \cfunction{register_objects} function searches the command line for
options of the form ``\option{-I~\optionarg{name}}'' and creates one object for
each such option.  In the code below, note that
\cfunction{data_phonebook_server} is the name of the server skeleton function
that was generated for you by Flick.  That is the function that dispatches
requests to objects that support the \idl{phonebook} interface defined in our
IDL\@.

\begin{verbatim}
   void register_objects(CORBA_ORB o, CORBA_BOA b, int argc, char **argv,
                         CORBA_Environment *ev)
   {
       int i;

       orb = o; /* Globals: save ORB and BOA handles for later use. */
       boa = b;

       pb_impl_list = 0;

       for (i = 1; i < argc; i++) {
           if (!strcmp(argv[i], "-I") && (i + 1 < argc)) {
               CORBA_ReferenceData id;
               data_phonebook obj;
               impl_node list = pb_impl_list;

               /* Register object with name `argv[i + 1]'. */
               id._length = strlen(argv[i + 1]);
               id._maximum = id._length;
               id._buffer = (CORBA_char *)
                             CORBA_alloc(id._maximum * sizeof(CORBA_char));
               if (!id._buffer) {
                   signal_no_memory(ev);
                   return;
               }
               memcpy(id._buffer, argv[i + 1], id._length);

               obj = CORBA_BOA_create(boa, &id,
                                      "data::phonebook",
                                      &data_phonebook_server,
                                      ev);
               if (ev->_major != CORBA_NO_EXCEPTION)
                   return;

               /* Add a corresponding `impl_node' to our list. */
               pb_impl_list = (impl_node)
                              malloc(sizeof(*pb_impl_list));
               if (!pb_impl_list) {
                   signal_no_memory(ev);
                   return;
               }

               pb_impl_list->id = id;
               pb_impl_list->obj = obj;
               pb_impl_list->pb = 0;
               pb_impl_list->pb_elems = 0;
               pb_impl_list->pb_size = 0;
               pb_impl_list->next = list;
           }
       }

       /* Signal failure if no objects were registered. */
       if (!pb_impl_list)
           signal_initialize(ev);
   }
\end{verbatim}

We are now ready to write the server ``work functions'' --- the functions that
implement the operations defined in our phonebook interface.  Abbreviated code
for the \cfunction{data_phonebook_add} function (implementing the \idl{add}
operation defined in our IDL) is shown below.  Complete source code for all the
work functions is contained in the \filename{phone-workfuncs.c} file in the
example source code directory.

\begin{verbatim}
   void data_phonebook_add(data_phonebook obj, data_entry *arg,
                           CORBA_Environment *ev)
   {
       /* Find the object implementation --- see `find_impl' below. */
       impl_node impl = find_impl(obj, ev);
       int i;

       /* If we failed to find the implementation, return. */
       if (ev->_major != CORBA_NO_EXCEPTION)
           return;

       /* See if this entry is already in the phonebook. */
       for (i = 0; i < impl->pb_size; ++i) {
           if (impl->pb[i] && !strcmp(impl->pb[i]->n, arg->n)) {
               /* Found a duplicate!  Raise a `data_duplicate' exception. */
               data_duplicate *d =
                   (data_duplicate *) CORBA_alloc(sizeof(data_duplicate));

               if (!d) {
                   signal_no_memory(ev); return;
               }
               d->p = (CORBA_char *) CORBA_alloc(strlen(impl->pb[i]->p) + 1);
               if (!d->p) {
                   CORBA_free(d); signal_no_memory(ev); return;
               }
               strcpy(d->p, impl->pb[i]->p);
               CORBA_BOA_set_exception(boa, ev, CORBA_USER_EXCEPTION,
                                       ex_data_duplicate, d);
               return;
           }
       }

       /* Find an empty entry in `impl'; grow the phonebook if necessary. */
       i = find_empty_entry(impl, ev);
       if (ev->_major != CORBA_NO_EXCEPTION)
           return;

       /*
        * Allocate memory for the new entry.  Note that we have to copy the
        * `arg' data because CORBA says we can't keep pointers into `in' data
        * after this function has returned.
        */
       impl->pb[i] = (data_entry *) malloc(sizeof(data_entry));
       if (!impl->pb[i]) {
           signal_no_memory(ev); return;
       }

       impl->pb[i]->n = (char *) malloc(sizeof(char) * (strlen(arg->n) + 1));
       impl->pb[i]->p = (char *) malloc(sizeof(char) * (strlen(arg->p) + 1));
       if (!(impl->pb[i]->n) || !(impl->pb[i]->p)) {
           /* Free what we have allocated and signal an exception. */
           ... ; return;
       }

       /* Copy the `arg' information into our phonebook. */
       strcpy(impl->pb[i]->n, arg->n);
       strcpy(impl->pb[i]->p, arg->p);

       /* Increment the number of entries in our phonebook. */
       impl->pb_elems++;

       /* Success! */
       return;
   }
\end{verbatim}

The above function calls \cfunction{find_impl} to find the node that represents
a phonebook, given its CORBA object reference.  That helper function is shown
below.

\begin{verbatim}
   impl_node find_impl(data_phonebook obj, CORBA_Environment *ev)
   {
       impl_node this_impl = pb_impl_list;
       CORBA_ReferenceData *obj_id = CORBA_BOA_get_id(boa, obj, ev);

       if (ev->_major != CORBA_NO_EXCEPTION)
           return 0;

       while (this_impl) {
           if ((this_impl->id._length == obj_id->_length)
               && !memcmp(this_impl->id._buffer,
                          obj_id->_buffer,
                          obj_id->_length))
               break;
           this_impl = this_impl->next;
       }
       if (!this_impl) {
           /* This should never be reached. */
           signal_object_not_exist(ev);
       }

       CORBA_free(obj_id->_buffer);
       CORBA_free(obj_id);

       return this_impl;
   }
\end{verbatim}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Client Program}
\label{subsec:Client Program}

For the phonebook client, Flick creates stubs that will send requests to the
server process and receive the server's replies.  You must write the client's
\cfunction{main} function.  Our client will be interactive, and its
\cfunction{main} function is shown below.  Note that our client uses
\cfunction{CORBA_ORB_string_to_object} to establish its connection to an object
that resides in the server.  Flick's IIOP runtime will cause the server to
print the names of its objects as they are registered.  The argument to our
client must be either the IOR-style or the URL-style name of an object in the
server; refer to Section~\ref{subsec:Creating Object References} for more
information about object names.

\begin{verbatim}
   int main(int argc, char **argv)
   {
       CORBA_ORB orb = 0;
       CORBA_Environment ev;
       data_phonebook obj;
       int sel, done;

       if (argc != 2) {
           fprintf(stderr, "Usage: %s <phone obj reference>\n", argv[0]);
           exit(1);
       }

       orb = CORBA_ORB_init(&argc, argv, 0, &ev);
       if (ev._major != CORBA_NO_EXCEPTION) {
           printf("Can't initialize the ORB.\n");
           exit(1);
       }

       obj = CORBA_ORB_string_to_object(orb, argv[1], &ev);
       if (ev._major != CORBA_NO_EXCEPTION) {
           printf("Can't convert `%s' into an object reference.\n",
                  argv[1]);
           exit(1);
       }

       done = 0;
       while (!done) {
           read_integer(("\n(1) Add an entry (2) Remove an entry "
                         "(3) Find a phone number (4) Exit: "),
                        &sel);
           switch(sel) {
           case 1:  add_entry(obj); break;
           case 2:  remove_entry(obj); break;
           case 3:  find_entry(obj); break;
           case 4:  done = 1; break;
           default: printf("Please enter 1, 2, 3, or 4.\n");
           }
       }
       return 0;
   }
\end{verbatim}

The client's \cfunction{add_entry} function invokes
\cfunction{data_phonebook_add}, which is the Flick-generated stub for the
\idl{add} operation.  It handles exceptions by calling the
\cfunction{handle_exception} function; the source for
\cfunction{handle_exception} can be found in the \filename{phonebook.c} file in
our example's source directory.

\begin{verbatim}
   void add_entry(data_phonebook obj)
   {
       data_entry e;
       char name[NAME_SIZE], phone[PHONE_SIZE];
       CORBA_Environment ev;

       e.n = name;
       e.p = phone;

       read_string("Enter the name: ", e.n, NAME_SIZE);
       read_string("Enter the phone number: ", e.p, PHONE_SIZE);

       data_phonebook_add(obj, &e, &ev);
       if (ev._major != CORBA_NO_EXCEPTION)
           handle_exception(&ev);
       else
           printf("`%s' has been added.\n", name);
   }
\end{verbatim}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Compiling the Application}
\label{subsec:CORBA:Compiling the Application}

The \filename{test/examples/phone/corba} directory contains a simple
\filename{Makefile} for compiling the phonebook server and client programs.
You will need to edit the \filename{Makefile} slightly in order to suit your
build environment.  Once that is done, and you have built Flick and the IIOP
runtime, you should be able to type \program{make} to build the CORBA
phonebook.  Two programs will be created: \program{phoneserver}, the server,
and \program{phonebook}, the client.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection{Using the Phonebook}
\label{subsec:CORBA:Using the Phonebook}

To run the application you must first start the phonebook server.  The server
expects to receive at least two arguments on the command line:

\begin{optionlist}
  \item[-OAport~\optionarg{portnumber}]
  %
  The port on which to run the server.

  \item[-I~\optionarg{name}]
  %
  The names of the object instances that the server will create.  This option
  may be repeated in order to create several object instances.  Each object
  must have a unique name.
\end{optionlist}

\noindent See Section~\ref{subsec:Server Command Line Options} for a list of
additional, optional arguments.  Once the \program{phoneserver} program is
running, you can invoke the \program{phonebook} program, giving it the IOR or
URL-style name of a server object.

\begin{verbatim}
   1 marker:~> phoneserver -OAport 1253 -I OfficeList -I DeptList
   Warning: no `-ORBipaddr' specified; using `marker.cs.utah.edu'.
   Object `OfficeList' is ready.
     URL:  iiop:1.0//marker.cs.utah.edu:1253/data::phonebook/OfficeList
     IOR:  IOR:0100000010000000646174613a3a70686f6e65626f6f6b0001000...
   Object `DeptList' is ready.
     URL:  iiop:1.0//marker.cs.utah.edu:1253/data::phonebook/DeptList
     IOR:  IOR:0100000010000000646174613a3a70686f6e65626f6f6b0001000...

   # Run a client on the same machine or on a different machine.

   1 fast:~> phonebook iiop:1.0//marker.cs.utah.edu:1253/...

   (1) Add an entry (2) Remove an entry (3) Find a phone number (4) Exit:
   ...
\end{verbatim}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% End of file.

