topical media & game development

talk show tell print

object-oriented programming

Hello (CORBA) Universe

CORBA is an impressive technology. It allows for writing heterogeneous platform-independent and language-independent client/server object systems. Most software developers, including those trained in object orientation, are unfamiliar with developing distributed applications. As a consequence, writing a CORBA application may seem to be beyond reach.

This example is meant to break that barrier, and to show the elementary steps to be taken in writing a CORBA application. To complicate matters a bit, we write a three-language system, consisting of three servers and three clients, written respectively in C++, Java and Prolog.


Hello (CORBA) Universe

H



slide: Hello (CORBA) Universe

Admittedly, the Hello Universe example presented here is slightly more complex than the Hello World example given in the appendix on Java.

In the example, it is shown in complete detail how to write clients and servers in the three respective languages, how to write a test program to test all possible combinations and how to manage the configuration of a CORBA application.

The example is based on the original Hello World example that came with Orbacus 3.1 from Object-Oriented Concepts and examples from the experimental SWI-Prolog CORBA binding for Orbacus 3.1.

The interface -- IDL

An interface written in IDL is the point of reference for every CORBA application. It informs the client what to expect from a server, and it tells the server what services it is to deliver.

The definition below defines a module universe that contains an interface named world. The world interface provides the method hello and two additional methods ask and tell.


  module universe { 
universe.idl
interface world {
world
void hello(); void ask(in string x); string tell(); oneway void halt(); }; };
The ask and tell methods were introduced to show how CORBA deals with in and out or result parameters.

In addition, the world interface supports a method halt, which was introduced to stop the world on the client's demand. In actual applications, you do not want to provide such a method without ensuring that the client has the right to stop the world.

C++ realization

The C++ realization consists of a broker that gives access to the ORB for the client and to both the ORB and the BOA for the server. Apart from a client and server, we need an implementation for the world, which is given in respectively the world-srv.h and world-srv.c files.

C++ realization


slide: C++ realization

Broker

The broker class in C++ provides a constructor, an initialization method, the operator that starts the server's event loop, and methods to convert strings to object references and methods to read and write object identifiers.

C++ broker -- class


  class broker { 
broker.h
public: broker(); void init(int& argc, char**& argv, int fl=0); // 1 = client int operator()(); // to run the server char* ref(corba::object* x); // object_to_string corba::object* ref(const char* s); // string_to object corba::object* object(const char* file); // get object IOR file void refout(const char* f, corba::object* x); // IOR to file };

slide: C++ broker -- class

Below, the implementation is given of the constructor, which needs to do nothing, the init method, that initializes the ORB, and the BOA in the case of a server.

C++ broker -- implementation


  broker::broker() { }  
broker.c
void broker::init(int& argc, char**& argv, int fl=0) { _orb = CORBA_ORB_init(argc, argv); if (!fl) _boa = _orb -> BOA_init(argc, argv); } } int broker::operator()() { _boa -> impl_is_ready(CORBA_ImplementationDef::_nil()); }

slide: C++ broker -- implementation

As said before, the broker class provides only shorthands and abstractions from vendor-specific code.

Client

The code snippet below shows how the client creates and initializes a broker object, how it obtains an object reference, and also some calls to the world server, including hello and a request to be informed about Clinton's affairs, which certainly had some relevance at the time of writing this.

C++ client


      int main(int argc, char* argv[], char*[]) { 
client.c
broker* _broker = new broker(); // get yourself a broker try { _broker->init(argc,argv); // initialize broker corba::object* obj = _broker->object("world.ref"); universe_world_var world = universe_world::_narrow(obj); { // some object invocations world -> hello(); world -> ask("How are Clinton's affairs?"); cout << "client:" << world->tell() << endl; } } catch(corba::exception ex) { ... } }

slide: client

Note that the object that is obtained from world.ref must be dynamically downcasted to its actual type.

Server

The server code is similar as far as the creation and initialization of the broker is concerned, but instead of creating an object from a string identifier, it writes the identity of the server object created to the file world.ref.

C++ server


  int main(int argc, char* argv[], char*[]) 
server.c
{ broker* _broker = new broker(); // get yourself a broker try { _broker->init(argc,argv); // initialize orb and boa universe_world_var p = new universe_world_srv; _broker->refout("world.ref", p); // write identity _broker->operator()(); // run the the world } catch(corba::exception& ex) { ... } }

slide: server

The C++ class that implements the world interface might appear disappointingly trivial. It is left to the student to think of something less trivial.

C++ world implementation


  void universe_world_srv::hello() {  
world_srv.c
cout << "Hello World!" << endl; } void universe_world_srv::ask(const char* s) { cout << "Asking: " << s << endl; } char* universe_world_srv::tell() { char result[] = "ok"; CORBA_String_var s = (const char*) result; return s._retn(); } void universe_world_srv::halt() { exit(0); }

slide: world-srv.c

Discussion

Writing a CORBA application might indeed be simpler than you thought. Follow the steps taken in this example as a recipe, and you master the art of writing CORBA applications instantly.

Java realization

The Java realization of the Hello Universe example has the same structure as the C++ realization. See slide java-realization.

Java realization


slide: Java realization

Broker

The IDL-Java binding seems to be somewhat better standardized, possibly because it is of a later date. So the advantage of using a broker abstraction lies primarily in the shorthands it provides, and the similarity with the C++ realization.

  import org.omg.CORBA.*; 
broker.java
import java.io.*; public class broker { boolean _fl = false; java.applet.Applet _applet = null; public broker() { } public broker(boolean fl) { _fl = fl; } public broker(java.applet.Applet x) { _applet = x; init(null); } public void init(String[] args) { if (_applet == null) { _orb = ORB.init(args,new java.util.Properties()); if (!_fl) _boa = _orb.BOA_init(args,new java.util.Properties()); } else _orb = ORB.init(_applet, null); } public int operator() {
run -- server-only
if (!_fl) _boa.impl_is_ready(null); return 0; // OK } .... };

slide: Java -- broker

The only (real) difference with the C++ broker class is the possible existence of an applet. Somewhat unfortunately, when the (client) object is an applet, the initialization of the ORB must be done in a different way.

Client

The client in Java must, also, create and initialize a broker object, and create a reference to the world server object.

Java -- client


  package universe;
  
  import org.omg.CORBA.*; 
client.java
import java.io.*; import hush.broker; // see broker.java public class client { public static void main(String args[]) { broker _broker = new broker(true); // true means client only try { _broker.init(args); // init orb org.omg.CORBA.Object obj = _broker.object("world.ref"); world world = worldHelper.narrow(obj); if (world == null) throw new RuntimeException(); System.out.println("Enter 'h' (hello) or 'x' (exit):"); ... // do some requests to the world } catch(...) { ... } } };

slide: Java -- client

In Java, an extra object interfaceHelper is created to allow for casting the object that is created from a string object identifier to its actual object type, world in this case.

Server

The server provides access to the (server) object that implements the world interface. After creating and initializing a broker object, it creates an instance of a world server and writes its object identifier to the file world.ref. In addition it writes a HTML file that contains an applet that has a (string) reference to the server. See the online version or the Orbacus documentation for details.

Java -- server


  package universe; 
server.java
import org.omg.CORBA.*; import java.io.*; import hush.broker; // see broker.java public class server { public static void main(String args[]) { broker _broker = new broker(); try { _broker.init(args); // create orb en boa; world_srv p = new world_srv(); // create impl object _broker.refout("world.ref",p); // write ref _broker.html("world.htm",p, // create world.htm " code=universe/applet.class " + "width=500 height=300"); _broker.operator(); // run == boa.impl_is_ready(null); } catch(SystemException ex) { _broker.print(ex); System.exit(1); } System.exit(0); } }
After creating the object and its reference files, the server invokes the method impl_is_ready, through the broker's operator.

The implementation of the actual world server is as simple as its C++ peer.

Java -- server implementation


  package universe; 
world_srv.java
import org.omg.CORBA.*; public class world_srv extends _worldImplBase { public void hello() { System.out.println("Hello World!"); } public void ask(String msg) { System.out.println(msg); } public String tell() { String s = new String("ok"); return s; } public void halt() { System.exit(0); } }
Note that dealing with strings is significantly simpler in Java, because of Java's higher-level built-in String.

Discussion

Observe that the Java and C++ realizations are very similar in structure and also very similar in code. Nevertheless, what does not become evident in this small example is the bookkeeping that needs to be done in C++ for managing the objects created. Since Java supports garbage collection, the programmer needs to do no such bookkeeping, whereas in C++ one has to use either reference counting or the special _var type, that acts as a smart pointer which does the reference counting automatically. See any CORBA documentation for details.

Prolog realization

Although Prolog is not a mainstream programming language in IT, it is interesting to look at the realization of the Hello Universe example in Prolog, if only to observe that its structure is very similar to the realization in Java and C++. In this example, that is implemented with the SWI-Prolog CORBA stubber, which generates most of the code, we will primarily look at the implementation of the server object itself. The relevance of this example may be motivated by the observation that many knowledge-intensive IT applications are realized by imperative (object-oriented) languages such as Java and C++ which are obviously not suited for that.

Prolog realization


slide: Prolog realization

For those that do not know Prolog it is sufficient to know that in Prolog so-called predicate definitions act as procedures, that may be invoked by trying to satisfy a goal. A special, very powerful, feature of Prolog is that

  broker(client(M:F)) :- 
broker.pl
... corba_initialize_orb([], _), factory(F). // gives a handle to the server object broker(server(M:I)) :- ... corba_initialize_server([server,server(test), timeout(infinite)],Server), ... // create server object G =.. [_Create,_Server,Self], call(G), corba_object_to_string(Self,IOR), open(IORFile,write,Fd), // write reference to file format(Fd,'string',[IOR]), close(Fd), corba_main_loop(Server). // enter main loop

slide: Prolog -- broker

Obviously, when looking at this code, some standardization of a CORBA binding for Prolog is desirable.

Client

The client makes a connection with the broker, gets a binding to the server object and calls some methods of that object.

  
client.pl
:- use_module(universe). // see universe.pl :- [broker]. // include broker main :- broker(client(universe:F)), // initialize the broker assert(client(factory(F))), run. run :- h, ask('What is the state of Clinton s affairs?'), write('Type h to say hallo, x to quit.'),nl. ask(X) :- client(factory(F)), write(client(ask(X))),nl, world_ask(F,X), world_tell(F,R), write(client(ans(R))),nl. h :- client(factory(F)), world_hello(F). q :- client(factory(F)), world_halt(F), halt. x :- halt.

slide: Prolog -- client

Server

The server is significantly simpler, due to the fact that all ugly details have been hidden in the broker.


  :- [broker]. 
server.pl
main :- broker(server(universe:world)).

slide: Prolog -- server

The implementation of the server object consists of a collection of predicate definitions (procedures), that have the interface or class name as a prefix.


Prolog -- implementation


  :- module('universe',[]). 
universe.pl
world_hello(_Self) :- write('Hello World'),nl. world_ask(_Self, X) :- write(asking(X)), nl. world_tell(_Self,Y) :- Y = 'logically, ok', write(telling(Y)),nl. world_halt(_Self) :- halt.

slide: Prolog -- implementation

As in the previous examples, the actual realization is admittedly simple.

Discussion

Prolog, also in its standard (that is, non-object-oriented form) is a powerful language for implementing knowledge-intensive applications. This example shows that CORBA applications can be realized also by using Prolog technology. I would welcome seeing real-life applications in which the knowledge programming part was written in Prolog or an object-oriented extension thereof (such as the language DLP).

Configure, make and test

Still a difficult aspect of CORBA programming, when you are not using an IDE, is to manage the creation and configuration of object files and executables. In the online version of the book you'll find all the details of the Makefile, the settings used for Orbacus, and a simple test shell, which allows for testing all nine possible combinations of clients and servers.

Configure, make and test


slide: Configure, make and test

Testing CORBA applications is significantly more difficult than testing stand-alone applications. This is due on the one hand to the fact that it concerns a distributed application, involving communication over a network, and on the other hand to the indirection that must take place within both the client and the server to invoke and answer methods over the object request broker software bus.

Conclusions

This concludes our simple CORBA example. It shows that CORBA is ripe to be exploited, on a small scale in practical student assignments, but, as testified by the literature, also on a large scale in business-critical applications.

Conclusions

  • CORBA is ripe to be exploited in OO -- the practicum
  • the broker is a useful abstraction
  • forget about the wiring - concentrate on application logic

slide: Conclusions

In a multi-lingual, and possibly multi-orb, environment the broker abstraction may act as an intermediary, providing a short-hand for common operations and abstracting from the details in which the language bindings and ORBs may differ.

As in other areas, in CORBA programming it is good advice to start small and grow incrementally. Develop your system in such a way that you can gradually forget about the wiring, and concentrate on the application logic instead.



(C) Æliens 04/09/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.