There are many ORB implementation out there, as well as simple examples how to utilize them. Most of the examples show the basiscs, many show also advanced features. This tutorial shows how to implement a distributed application with three different ORBs involved.
This is not a tutorial about basics of CORBA. This is a tutorial about how to put several ORBs to work together. For an introduction into CORBA or a particular ORB, read one of the many books or the documentation of the ORB of your choise.
As mentioned above this tutorial uses three ORBs:
Please see Links for links to the resources on the net. We will see how to implement and start each of them as server as well as client, not at the same time of course.
Please note that this tutorial is not for beginners in programming, experience at least in C++ and basic knowledge about CORBA are expected. You will need experience in compiling source code, running command prompts and reading error message from the compiler (if anything goes wrong). Examples are held in C++ and Java. There are other CORBA bindings but not covered by this tutorial.
This chapter shows for every used ORB the implementations for client and server. The distributed object we will going to use is defined in the file:
hello.idl
:
interface Hello
{
string say_hello(in string client);
};
The interface is not very complex. The intention is that the client sends a string (its identification) to the server (parameter client), the server prints it out (stdout) and send back it own identification. This behaviour will be implemented in the following sections, one for each ORB.
There are four files, implementing client and server:
File | Description |
---|---|
client.cpp |
The client program |
server.cpp |
The server program |
Hello_impl.h |
The class delcaration of the implementation for the distributed object |
Hello_impl.cpp |
The implementation of the class for the distributed object |
The following picture shows the dependencies of files, generated and existing.
This subsection shows the source codes of all files needed to build the client and server programs.
Hello_impl.h
:
#ifndef __HELLO_IMPL_H__
#define __HELLO_IMPL_H__
#include "hello.hh"
class Hello_impl : public POA_Hello
{
public:
virtual char * say_hello(const char * client);
};
#endif
Hello_impl.cpp
:
#include "Hello_impl.h"
#include <iostream>
using namespace std;
char * Hello_impl::say_hello(const char * client)
{
cout << "omniORB C++ server: " << client << endl;
char * server = CORBA::string_alloc(32);
strncpy(server, "omniORB C++ server", 32);
return server;
}
client.cpp
:
#include "hello.hh"
#include <iostream>
#include <CORBA.h>
#include <Naming.hh>
using namespace std;
int main(int argc, char ** argv)
{
try {
// init ORB
CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);
// resolve service
Hello_ptr hello = 0;
try {
CORBA::Object_var ns_obj = orb->resolve_initial_references("NameService");
if (!CORBA::is_nil(ns_obj)) {
CosNaming::NamingContext_ptr nc = CosNaming::NamingContext::_narrow(ns_obj);
CosNaming::Name name;
name.length(1);
name[0].id = CORBA::string_dup("TestServer");
name[0].kind = CORBA::string_dup("");
CORBA::Object_ptr obj = nc->resolve(name);
if (!CORBA::is_nil(obj)) {
hello = Hello::_narrow(obj);
}
}
} catch (CosNaming::NamingContext::NotFound &) {
cerr << "not found" << endl;
} catch (CosNaming::NamingContext::InvalidName &) {
cerr << "invalid name" << endl;
} catch (CosNaming::NamingContext::CannotProceed &) {
cerr << "cannot proceed" << endl;
}
if (!CORBA::is_nil(hello)) {
char * server = hello->say_hello("omniORB C++ client");
cout << "answer from: " << server << endl;
CORBA::string_free(server);
}
// destroy ORB
orb->destroy();
} catch (CORBA::UNKNOWN) {}
}
server.cpp
:
#include "Hello_impl.h"
#include <iostream>
#include <CORBA.h>
#include <Naming.hh>
using namespace std;
int main(int argc, char ** argv)
{
try {
// init ORB
CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);
// init POA
CORBA::Object_var poa_obj = orb->resolve_initial_references("RootPOA");
PortableServer::POA_var poa = PortableServer::POA::_narrow(poa_obj);
PortableServer::POAManager_var manager = poa->the_POAManager();
// create service
Hello_impl * service = new Hello_impl;
// register within the naming service
try {
CORBA::Object_var ns_obj = orb->resolve_initial_references("NameService");
if (!CORBA::is_nil(ns_obj)) {
CosNaming::NamingContext_ptr nc = CosNaming::NamingContext::_narrow(ns_obj);
CosNaming::Name name;
name.length(1);
name[0].id = CORBA::string_dup("TestServer");
name[0].kind = CORBA::string_dup("");
nc->rebind(name, service->_this());
cout << argv[0] << ": server 'TestServer' bound" << endl;
}
} catch (CosNaming::NamingContext::NotFound &) {
cerr << "not found" << endl;
} catch (CosNaming::NamingContext::InvalidName &) {
cerr << "invalid name" << endl;
} catch (CosNaming::NamingContext::CannotProceed &) {
cerr << "cannot proceed" << endl;
}
// run
manager->activate();
orb->run();
// clean up
delete service;
// quit
orb->destroy();
} catch (CORBA::UNKNOWN) {
cerr << "unknown exception" << endl;
} catch (CORBA::SystemException &) {
cerr << "system exception" << endl;
}
}
Sure, there is a Makefile but this subsection shows what steps are necessary to build the client and server programs manually.
hello.idl
:$ g++ -c client.cpp -I$OMNIORB_HOME/include -I$OMNIORB_HOME/include/omniORB4
$ g++ -c server.cpp -I$OMNIORB_HOME/include -I$OMNIORB_HOME/include/omniORB4
$ g++ -c Hello_impl.cpp -I$OMNIORB_HOME/include -I$OMNIORB_HOME/include/omniORB4
$ g++ -c helloSK.cc -I$OMNIORB_HOME/include -I$OMNIORB_HOME/include/omniORB4
There are four files, implementing client and server:
File | Description |
---|---|
client.cpp |
The client program |
server.cpp |
The server program |
Hello_impl.h |
The class delcaration of the implementation for the distributed object. Exactly the same as for omniORB |
Hello_impl.cpp |
The implementation of the class for the distributed object |
Those seem to be the same files as for omniORB. Although the names and the logic are the same there are minor differences.
The following picture shows the dependencies of files, generated and existing.
This subsection shows the source codes of all files needed to build the client and server programs.
Hello_impl.h
:
#ifndef __HELLO_IMPL_H__
#define __HELLO_IMPL_H__
#include "hello.hh"
class Hello_impl : public POA_Hello
{
public:
virtual char * say_hello(const char * client);
};
#endif
Hello_impl.cpp
:
#include "Hello_impl.h"
#include <iostream>
using namespace std;
char * Hello_impl::say_hello(const char * client)
{
cout << "MICO C++ server: " << client << endl;
char * server = CORBA::string_alloc(32);
strncpy(server, "MICO C++ server", 32);
return server;
}
client.cpp
:
#include "hello.hh"
#include <iostream>
#include <CORBA.h>
#include <mico/CosNaming.h>
using namespace std;
int main(int argc, char ** argv)
{
try {
// init ORB
CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);
// resolve service
Hello_ptr hello = 0;
try {
CORBA::Object_var ns_obj = orb->resolve_initial_references("NameService");
if (!CORBA::is_nil(ns_obj)) {
CosNaming::NamingContext_ptr nc = CosNaming::NamingContext::_narrow(ns_obj);
CosNaming::Name name;
name.length(1);
name[0].id = CORBA::string_dup("TestServer");
name[0].kind = CORBA::string_dup("");
CORBA::Object_ptr obj = nc->resolve(name);
if (!CORBA::is_nil(obj)) {
hello = Hello::_narrow(obj);
}
}
} catch (CosNaming::NamingContext::NotFound &) {
cerr << "not found" << endl;
} catch (CosNaming::NamingContext::InvalidName &) {
cerr << "invalid name" << endl;
} catch (CosNaming::NamingContext::CannotProceed &) {
cerr << "cannot proceed" << endl;
}
if (!CORBA::is_nil(hello)) {
char * server = hello->say_hello("MICO C++ client");
cout << "answer from: " << server << endl;
CORBA::string_free(server);
}
// destroy ORB
orb->destroy();
} catch (CORBA::UNKNOWN) {}
}
server.cpp
:
#include "Hello_impl.h"
#include <iostream>
#include <CORBA.h>
#include <mico/CosNaming.h>
using namespace std;
int main(int argc, char ** argv)
{
try {
// init ORB
CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);
// init POA
CORBA::Object_var poa_obj = orb->resolve_initial_references("RootPOA");
PortableServer::POA_var poa = PortableServer::POA::_narrow(poa_obj);
PortableServer::POAManager_var manager = poa->the_POAManager();
// create service
Hello_impl * service = new Hello_impl;
// register within the naming service
try {
CORBA::Object_var ns_obj = orb->resolve_initial_references("NameService");
if (!CORBA::is_nil(ns_obj)) {
CosNaming::NamingContext_ptr nc = CosNaming::NamingContext::_narrow(ns_obj);
CosNaming::Name name;
name.length(1);
name[0].id = CORBA::string_dup("TestServer");
name[0].kind = CORBA::string_dup("");
nc->rebind(name, service->_this());
cout << argv[0] << ": server 'TestServer' bound" << endl;
}
} catch (CosNaming::NamingContext::NotFound &) {
cerr << "not found" << endl;
} catch (CosNaming::NamingContext::InvalidName &) {
cerr << "invalid name" << endl;
} catch (CosNaming::NamingContext::CannotProceed &) {
cerr << "cannot proceed" << endl;
}
// run
manager->activate();
orb->run();
// clean up
delete service;
// quit
orb->destroy();
} catch (CORBA::UNKNOWN) {
cerr << "unknown exception" << endl;
} catch (CORBA::SystemException &) {
cerr << "system exception" << endl;
}
}
There is a Makefile, but this subsection shows how to build the client and server programs manually.
hello.idl
:$ g++ -c client.cpp -I$MICO_HOME/include
$ g++ -c server.cpp -I$MICO_HOME/include
$ g++ -c Hello_impl.cpp -I$MICO_HOME/include
$ g++ -c hello.cc -I$MICO_HOME/include
There are three files, implementing client and server. This version needs one less because Java combines header (.h
) and definition (.cpp
/.cc
) files into one (.java
).
File | Description |
---|---|
client.java |
The client program |
server.java |
The server program |
Hello_impl.java |
The class of the implementation for the distributed object. |
The following picture shows the dependencies of files, generated and existing.
This subsection shows the source codes of all files needed to build the client and server programs.
Hello_impl.java
:
import java.util.*;
public class Hello_impl extends HelloPOA {
public java.lang.String say_hello(java.lang.String client) {
System.out.println("Java Server: " + client);
return "Java Server";
}
}
client.java
:
import java.util.*;
public class client {
public static void main(String [] args) {
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null);
if (orb == null) System.exit(-1);
try {
// obtain service from naming server
org.omg.CORBA.Object ns_obj = orb.resolve_initial_references("NameService");
org.omg.CosNaming.NamingContext nc
= org.omg.CosNaming.NamingContextHelper.narrow(ns_obj);
org.omg.CosNaming.NameComponent [] path
= { new org.omg.CosNaming.NameComponent("TestServer", "") };
org.omg.CORBA.Object obj = nc.resolve(path);
Hello hello = HelloHelper.narrow(obj);
// use service
String server = hello.say_hello("Java client");
System.out.println("answer from: " + server);
// destroy
orb.destroy();
} catch (org.omg.CORBA.ORBPackage.InvalidName exception) {
exception.printStackTrace(System.out);
} catch (org.omg.CosNaming.NamingContextPackage.NotFound exception) {
exception.printStackTrace(System.out);
} catch (org.omg.CosNaming.NamingContextPackage.CannotProceed exception) {
exception.printStackTrace(System.out);
} catch (org.omg.CosNaming.NamingContextPackage.InvalidName exception) {
exception.printStackTrace(System.out);
} catch (org.omg.CORBA.COMM_FAILURE exception) {
exception.printStackTrace(System.out);
} catch (Exception exception) {
exception.printStackTrace(System.out);
}
}
}
server.java
:
import java.util.*;
public class server {
public static void main(String [] args) {
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null);
if (orb == null) System.exit(-1);
try {
// init POA
org.omg.CORBA.Object poa_obj = orb.resolve_initial_references("RootPOA");
org.omg.PortableServer.POA poa
= org.omg.PortableServer.POAHelper.narrow(poa_obj);
org.omg.PortableServer.POAManager manager = poa.the_POAManager();
// create service
org.omg.CORBA.Object service = poa.servant_to_reference(new Hello_impl());
// register within naming service
try {
org.omg.CORBA.Object ns_obj = orb.resolve_initial_references("NameService");
if (ns_obj != null) {
org.omg.CosNaming.NamingContext nc
= org.omg.CosNaming.NamingContextHelper.narrow(ns_obj);
org.omg.CosNaming.NameComponent [] name
= new org.omg.CosNaming.NameComponent[1];
name[0] = new org.omg.CosNaming.NameComponent("TestServer", "");
nc.rebind(name, service);
System.out.println("Server 'TestServer' bound");
}
} catch (Exception exception) {
exception.printStackTrace(System.out);
}
// run
manager.activate();
orb.run();
// destroy
orb.destroy();
} catch (org.omg.CORBA.UNKNOWN exception) {
exception.printStackTrace(System.out);
} catch (org.omg.CORBA.SystemException exception) {
exception.printStackTrace(System.out);
} catch (Exception exception) {
exception.printStackTrace(System.out);
}
}
}
There is a Makefile, but this subsection shows how to build the client and server programs manually.
hello.idl
:This chapter shows how to run the programs in different configurations. However, there are many combinations but not all are shown. We have three naming servers (one from each ORB), three servers and three clients.
The following examples are shown below:
The best choice is to run Naming Server, Server and Client in separate shells.
If you like to build all necessary party using the provided Makefile, you will have to define three environment variables:
OMNIORB_HOME
: directory in which omniORB was installedMICO_HOME
: directory in which MICO was installedJAVA_HOME
: directory in which Java SDK was installedInstead of defining those variables you may specify them at the command prompt while starting the make tool:
Probably you will need to specify additional search paths, one to the binaries of the two ORBs (omniORB, MICO) and one to the Java SDK (which contains its own ORB).
Naming Server: omniORB (Default port: 2809)
Server: omniORB
Client: omniORB
Client: MICO
Client: Java
Naming Server: omniORB (Default port: 2809)
Server: MICO
Client: omniORB
Client: MICO
Client: Java
Naming Server: MICO
Server: omniORB
Client: omniORB
Client: MICO
The Naming Service depends on the implementation.
The server side is pretty much always the same.
The client side is pretty much always the same.
All ORBs have their own extensions and additional features. This is shown mostly in their handling of the services. Server and Client are, as long as they are programmed according to the CORBA standard, independent. As shown in the examples above, they are interchangeable.
All files provided by this page are free to modify, distribute or to use them in any kind you like. Use them on your own risk.