All Manuals > Developing Component Software with CORBA® > 2 Quick Start Tutorial

2.1 A CORBA-based Hello World

This chapter's example is an implementation of the standard Hello World application, using Common Lisp and CORBA. In this version of Hello World, a client application asks a server application for a string. When the client receives the string, it prints it to the standard output, and then exits.

We will take these basic steps to create the application:

  1. Define the interface.

    We define the interface to the server using OMG's Interface Definition Language (IDL).

  2. Implement the client.
  3. Implement the server.
  4. Build and test the application.

The complete Hello World application is here:

(example-edit-file "corba/hello-world/")

For instance, in a default 64-bit LispWorks 8.0 installation on Microsoft Windows, the location is C:\Program Files\LispWorks\lib\8-0-0-0\examples\corba\hello-world\.

2.1.1 Defining the interface

We first need to define the interface of the Hello World server object. The client and server will communicate across this interface. The interface is defined using IDL in a single file that must have the extension .idl.

  1. Create a file called hello-world.idl.
  2. Enter the IDL declaration below into the hello-world.idl file.
    module HelloWorld {
      interface world {
        string hello();
      };
    };
    

This IDL declaration says that there are CORBA objects of a kind called world, and that there is an operation called hello on world objects that takes no arguments and returns a string. Servers implement world, and clients call hello on instances of world.

Now that we have written the IDL, we can run the IDL parser over it to produce stub and skeleton code for the client and server parts of the application.

2.1.2 Generating the stub and skeleton code from IDL

We need the IDL parser to parse the IDL to generate appropriate stubs and skeletons. We do this by including the IDL file in the defsystem that defines the code we are writing. For Hello World, the relevant defsystem is:

(defsystem hello-world-corba-object ()
  :members (
            ("hello-world" :type :idl-file)))

The defsystem utility has been extended to correctly handle a file of type idl-file. In this case, the fasl corresponding to the IDL file contains the compiled stubs and skeletons for the given IDL and is generated when we compile the system.

To create a defsystem file for the Hello World application:

  1. Create a defsystem file called defsys.lisp.
  2. Enter the following Lisp code into the defsys.lisp file:
    (in-package "CL-USER")
     
    (require "corba-orb")
     
    (defsystem hello-world-corba-object ()
      :members (
                ("hello-world" :type :idl-file)
                ))
      :rules ((:in-order-to :compile :all
              (:requires (:load :previous)))))
    
  3. Save and close the defsystem file.

When it comes time to run the application, stubs and skeletons will be generated.

2.1.3 Defining utilities for sharing an object reference

Now we will define some utilities for communicating an object reference from the server to the client by converting the object reference into a string using ORB-supplied functions and writing it to a shared file. The client can then read the string from the shared file and convert it back into an object reference. Note that a real application would probably use a higher level service such as a Name Service for passing object references between applications.

  1. Create a file called shared.lisp.
  2. Enter the following Common Lisp code into the shared.lisp file:
    (in-package "CL-USER")
     
    (defparameter *hello-world-ior-file* 
      #+mswindows "c:/temp/hello.ior"
      #-mswindows "/tmp/hello.ior")
     
    (defun object-to-file (orb object)
      (with-open-file (st *hello-world-ior-file* :direction :output
                                              :if-exists :supersede)
        (prin1 (op:object_to_string orb object) st)))
     
    (defun file-to-object (orb)
      (with-open-file (st *hello-world-ior-file*)
        (op:string_to_object orb (read st))))
    

    This code does the following:

    • object-to-file opens the shared file and uses the op:object_to_string function to convert the object reference into a string, which is then written into the file.
    • file-to-object performs the inverse operation: it reads the string from the file and uses op:string_to_object to convert the string back into a client-side proxy object.
  3. Save and close the shared.lisp file.
  4. Add shared.lisp to the defsystem by adding one line of code to the defsys.lisp file, which should then look like this:
    (in-package "CL-USER")
     
    (require "corba-orb")
     
    (defsystem hello-world-corba-object ()
      :members (
                ("hello-world" :type :idl-file)
                "shared"
                ))
      :rules ((:in-order-to :compile :all
              (:requires (:load :previous)))))
    

2.1.4 Implementing the client

Now we will implement the client side of the Hello World application. We create a file hello-world-client.lisp and add it to the defsystem. (You can implement this as you wish, but here is one possible implementation.)

  1. Create a file called hello-world-client.lisp.
  2. Enter the following Common Lisp code into the
    hello-world-client.lisp file:
    (in-package "CL-USER")
     
    (defun run-client ()
      (let ((orb (op:orb_init nil "LispWorks ORB")))
        (let ((world (op:narrow 'HelloWorld:world (file-to-object
                                                   orb))))
          (format t "~S~%" (op:hello world)))))
    

    This code does the following:

    • Gets a world object from somewhere.
    • Invokes op:hello on the object to get a string.
    • Writes out the string and a new line to the standard output stream.

    The elided details are not important at this stage, they involve getting an object reference from somewhere. In the full source at the end of this chapter (2.2 Complete source code for the Hello World example) you can see that a shared file is used to pass a stringified object reference.

  3. Save and close the hello-world-client.lisp file.
  4. Add hello-world-client to the defsystem by adding one line of code to the defsys.lisp file, which should then look like this:
    (in-package "CL-USER")
     
    (require "corba-orb")
     
    (defsystem hello-world-corba-object ()
      :members (
                ("hello-world" :type :idl-file)
                "shared"
                "hello-world-client"
                ))
      :rules ((:in-order-to :compile :all
              (:requires (:load :previous)))))
    

2.1.5 Implementing the server

Implementing the server is also easy. We create a file
hello-world-server.lisp.

In the server the main function is less interesting because it is concerned with the administrative details of writing out a stringified form of the object reference into the shared file and initializing the server. The actual core of the application implementation is:

(defclass world-implementation (HelloWorld:world-servant) ()) 
 
(corba:define-method op:hello ((self world-implementation))
  (declare (ignore self))
  "Hello World!")

This subclasses a special generated class on the server side called a servant, and then implements a method on op:hello that actually returns the desired string.

  1. Create a file called hello-world-server.lisp.
  2. Enter the following code into hello-world-server.lisp:
    (in-package "CL-USER")
     
    (defclass world-implementation (HelloWorld:world-servant) ())
     
    (corba:define-method op:hello ((self world-implementation))
      (declare (ignore self))
      "Hello World!")
     
    (defun server-startup ()
      (let* ((orb (op:orb_init nil "LispWorks ORB"))
             (poa (op:resolve_initial_references orb "RootPOA"))
             (impl (make-instance 'world-implementation))
             (world (op:narrow 'HelloWorld:world
                               (op:servant_to_reference poa impl))))
        (object-to-file orb world)
        (let ((manager (op:the_poamanager poa)))
          (op:activate manager))))
    
  3. Add hello-world-server to the defsystem by adding one line of code to the defsys.lisp file, which should then look like this:
    (in-package "CL-USER")
     
    (require "corba-orb")
     
    (defsystem hello-world-corba-object ()
      :members (
                ("hello-world" :type :idl-file)
                "shared"
                "hello-world-server"
                "hello-world-client"
                ))
      :rules ((:in-order-to :compile :all
              (:requires (:load :previous)))))
    

2.1.6 Building and testing the application

To build and test this distributed Hello World application, you must copy the rest of the source code from 2.2 Complete source code for the Hello World example into the respective files. The code can also be found in the corba/hello-world subdirectory of the standard examples directory.

After supplementing your files with the complete source code, perform the following steps in the Listener to run the example:

  1. Load the defsystem file by entering:
    (load (example-file "corba/hello-world/defsys"))
    (compile-system "HELLO-WORLD-CORBA-OBJECT"
                    :t-dir (get-temp-directory)
                    :load t)
    

    Now, you can run the application to test that it works.

  2. If you are using LispWorks on a UNIX platform and not running with multiprocessing enabled, then call:
    (mp:initialize-multiprocessing)
    
  3. You need to run the server first so that it is waiting and ready to receive calls from the client.

    Enter the command:

    (cl-user::server-startup)
    
  4. You can then run the client using:
    (cl-user::run-client)
    

Note that you do not have to be running the client and the server in the same Lisp image (although you can if desired). In the simple example we have just implemented, they must be running on the same machine (to allow the object reference to be shared using a single file), but we have true location transparency in the way the client can be written with no regard for the location of the server process.


Developing Component Software with CORBA® - 01 Dec 2021 19:38:36