CORBA

From XennisWiki
Jump to: navigation, search

The Common Object Request Broker Architecture (CORBA) is a standard defined by the Object Management Group (OMG) that enables software components written in multiple computer languages and running on multiple computers to work together (i.e., it supports multiple platforms). (Wikipedia)

Example - server-client with C++ and Java

Further help: CORBA Tutorial: Connecting 3 ORBs, Java IDL: The "Hello World" Example (Java only), CORBA, C++ and Linux

See also: CORBA - Advanced example with server-client in Java and C++

Definition of the IDL for all remote methods. All distirbuted object have to defined in this file.

example.idl

interface ExampleInterface
{
	string send_message(in string message);
};

Setup

As operation system I used Lubuntu 13.04 (a lightweight version of Ubuntu (in a virtual machine).

We want to write in C++ and Java. That is why, you need the C++ compiler g++ and the Java JDK (openjdk-7-jdk). You can install both by:

sudo apt-get install g++
sudo apt-get install openjdk-7-jdk

Install omniORB

CORBA is already integrated in JAVA and you don't need to install something extra for this. To install OmniORB, a C++ implementation of CORBA, type in the command line:

sudo apt-get install omniidl omniorb omniorb-nameserver omniorb-idl libomniorb4-dev libomniorb4-1

After the installation you have to configure omniORB by editing the file /etc/omniORB.cfg. First setup the InitRef. In this example we use the localhost with the port number 4333:

InitRef = NameService=corbaname::localhost:4333

Second active the the supportBootstrapAgent by set it equal one to allow the communication with Java:

supportBootstrapAgent = 1

C++ (omniORB)

Files

  • server.cpp server programm
  • client.cpp client programm
  • MyExampleInterface_impl implementation of the class for distirbuted objects
  • MyExampleInterface_impl.h header for Example_impl.cpp

Interface Implementation

MyExampleInterface_impl.h

#ifndef __MY_EXAMPLE_INTERFACE_IMPL_H__
#define __MY_EXAMPLE_INTERFACE_IMPL_H__

#include "example.hh"

class MyExampleInterface_impl : public POA_ExampleInterface
{
	public:
		virtual char * send_message(const char * message);
};

#endif // __MY_EXAMPLE_INTERFACE_IMPL_H__

MyExampleInterface_impl_impl.cpp

#include "MyExampleInterface_impl.h"
#include <iostream>

using namespace std;

char * MyExampleInterface_impl::send_message(const char * message)
{
	cout << "C++ (omniORB) server: " << message << endl;
	char * server = CORBA::string_alloc(42);
	strncpy(server, "Message from C++ (omniORB) server", 42);
	return server;
}

Server

Implementation of the Server

server.cpp

#include "MyExampleInterface_impl.h"
#include <iostream>
#include <CORBA.h>
#include <Naming.hh>

/** Server name, clients needs to know this name */
#define SERVER_NAME		"MyServerName"

using namespace std;

int main(int argc, char ** argv)
{
	try {

		//------------------------------------------------------------------------
		// Initialize CORBA ORB
		//------------------------------------------------------------------------
		CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);

		//------------------------------------------------------------------------
		// Initialize POA: Get reference to root POA
		//
		// Servant must register with POA in order to be made available for client
		// Get reference to the RootPOA.
		//-----------------------------------------------------------------------
		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
		//------------------------------------------------------------------------
		MyExampleInterface_impl * service = new MyExampleInterface_impl;

		try {
			//------------------------------------------------------------------------
			// Bind object to name service as defined by directive InitRef
			// and identifier "NameService" in config file omniORB.cfg.
			//------------------------------------------------------------------------
			CORBA::Object_var ns_obj = orb->resolve_initial_references("NameService");
			if (!CORBA::is_nil(ns_obj)) {
				//------------------------------------------------------------------------
				// Narrow this to the naming context
				//------------------------------------------------------------------------
				CosNaming::NamingContext_ptr nc = CosNaming::NamingContext::_narrow(ns_obj);

				//------------------------------------------------------------------------
				// Bind to CORBA name service. Same name to be requested by client.
				//------------------------------------------------------------------------
				CosNaming::Name name;
				name.length(1);
				name[0].id = CORBA::string_dup(SERVER_NAME);
				name[0].kind = CORBA::string_dup("");
				nc->rebind(name, service->_this());

				//------------------------------------------------------------------------
				// Intizialization ready, server runs
				//------------------------------------------------------------------------				
				cout << argv[0] << " C++ (omniORB) server '" << SERVER_NAME << "' is running .." << endl;
			}
		} catch (CosNaming::NamingContext::NotFound &) {
			cerr << "Caught CORBA exception: not found" << endl;
		} catch (CosNaming::NamingContext::InvalidName &) {
			cerr << "Caught CORBA exception: invalid name" << endl;
		} catch (CosNaming::NamingContext::CannotProceed &) {
			cerr << "Caught CORBA exception: cannot proceed" << endl;
		}

		//------------------------------------------------------------------------
		// Activate the POA manager
		//------------------------------------------------------------------------
		manager->activate();

		//------------------------------------------------------------------------
		// Accept requests from clients
		//------------------------------------------------------------------------
		orb->run();

		//------------------------------------------------------------------------
		// Clean up
		//------------------------------------------------------------------------
		delete service;

		//------------------------------------------------------------------------
		// Destroy ORB
		//------------------------------------------------------------------------
		orb->destroy();

	} catch (CORBA::UNKNOWN) {
		cerr << "Caught CORBA exception: unknown exception" << endl;
	} catch (CORBA::SystemException &) {
		cerr << "Caught CORBA exception: system exception" << endl;
	}
}

Client

Implementation of the client

client.cpp

#include "example.hh"
#include <iostream>
#include <CORBA.h>
#include <Naming.hh>

/** Name is defined in the server.cpp */
#define SERVER_NAME		"MyServerName"

using namespace std;

int main(int argc, char ** argv)
{
	try {
		//------------------------------------------------------------------------
		// Initialize ORB object.
		//------------------------------------------------------------------------
		CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);

		//------------------------------------------------------------------------
		// Resolve service
		//------------------------------------------------------------------------
		ExampleInterface_ptr service_server = 0;

		try {

			//------------------------------------------------------------------------
			// Bind ORB object to name service object.
			// (Reference to Name service root context.)
			//------------------------------------------------------------------------
			CORBA::Object_var ns_obj = orb->resolve_initial_references("NameService");

			if (!CORBA::is_nil(ns_obj)) {
				//------------------------------------------------------------------------
				// Bind ORB object to name service object.
				// (Reference to Name service root context.)
				//------------------------------------------------------------------------
				CosNaming::NamingContext_ptr nc = CosNaming::NamingContext::_narrow(ns_obj);
				
				//------------------------------------------------------------------------
				// The "name text" put forth by CORBA server in name service.
				// This same name ("MyServerName") is used by the CORBA server when
				// binding to the name server (CosNaming::Name).
				//------------------------------------------------------------------------
				CosNaming::Name name;
				name.length(1);
				name[0].id = CORBA::string_dup(SERVER_NAME);
				name[0].kind = CORBA::string_dup("");

				//------------------------------------------------------------------------
				// Resolve "name text" identifier to an object reference.
				//------------------------------------------------------------------------
				CORBA::Object_ptr obj = nc->resolve(name);

				if (!CORBA::is_nil(obj)) {
					service_server = ExampleInterface::_narrow(obj);
				}
			}
		} catch (CosNaming::NamingContext::NotFound &) {
			cerr << "Caught corba not found" << endl;
		} catch (CosNaming::NamingContext::InvalidName &) {
			cerr << "Caught corba invalid name" << endl;
		} catch (CosNaming::NamingContext::CannotProceed &) {
			cerr << "Caught corba cannot proceed" << endl;
		}

		//------------------------------------------------------------------------
		// Do stuff
		//------------------------------------------------------------------------
		if (!CORBA::is_nil(service_server)) {
			char * server = service_server->send_message("Message from C++ (omniORB) client");
			cout << "response from Server: " << server << endl;
			CORBA::string_free(server);
		}

		//------------------------------------------------------------------------
		// Destroy OBR
   		//------------------------------------------------------------------------
		orb->destroy();

	} catch (CORBA::UNKNOWN) {
		cerr << "Caught CORBA exception: unknown exception" << endl;
	}
}

Build

Generate files from the interface desccription example.idl

omniidl -bcxx example.idl

omniidl will create files

  • example.hh
  • exampleSK.cc

The easiest way to build and compile all files ist to use the cpp/Makefile[1]

# Makefile

OMNIORB_HOME=/usr

IDL=$(OMNIORB_HOME)/bin/omniidl
IDLFLAGS=-bcxx

INCLUDES=-I$(OMNIORB_HOME)/include -I$(OMNIORB_HOME)/include/omniORB4

LIBS=-L$(OMNIORB_HOME)/lib -lomnithread -lomniORB4

IDL_FILE = ../example.idl

.PHONY: all
all: server client

server: server.o MyExampleInterface_impl.o exampleSK.o
	$(CXX) -o $@ $^ $(LIBS)

server.o: server.cpp MyExampleInterface_impl.h

MyExampleInterface_impl.h: example.hh

client: client.o exampleSK.o
	$(CXX) -o $@ $^ $(LIBS)

MyExampleInterface_impl.o: MyExampleInterface_impl.cpp MyExampleInterface_impl.h example.hh

exampleSK.o: exampleSK.cc example.hh

exampleSK.cc example.hh: $(IDL_FILE)
	$(IDL) $(IDLFLAGS) $<

.PHONY: clean
clean:
	find . -maxdepth 1 -type f -name "*.bak" -exec rm -f {} \;
	find . -maxdepth 1 -type f -name "*.o" -exec rm -f {} \;
	find . -maxdepth 1 -type f -name "*.stackdump" -exec rm -f {} \;
	find . -maxdepth 1 -type f -name "*.exe" -exec rm -f {} \;
	find . -maxdepth 1 -type f -name "example.hh" -exec rm -f {} \;
	find . -maxdepth 1 -type f -name "exampleSK.cc" -exec rm -f {} \;

.cpp.o:
	$(CXX) $(CXXFLAGS) -o $@ -c $< $(INCLUDES)

.cc.o:
	$(CXX) $(CXXFLAGS) -o $@ -c $< $(INCLUDES)

Execute

  • NameServer
sudo omniNames -start 4333 -logdir ~/omnilog/ -errlog ~/omnilog/omniNamesError.txt
sudo omniNames -logdir ~/omnilog/ -errlog ~/omnilog/omniNamesError.txt
  • Server
./server -ORBInitRef NameService=corbaloc::localhost:4333/NameService
  • Client
./client -ORBInitRef NameService=corbaloc::localhost:4333/NameService

Java

More Help: Java IDL: The "Hello World" Example

Files

  • server.cpp server programm
  • client.cpp client programm
  • MyExampleInterface_impl.java class of the implementation for distirbuted objects

Interface Implementation

MyExampleInterface_impl.java

public class MyExampleInterface_impl extends ExampleInterfacePOA {

	@Override
	public String send_message(String message) {
		System.out.println("Java Server: " + message);
		return "Message from Java server";
	}
}

Server

server.java

import java.util.*;

import org.omg.CORBA.ORB;
import org.omg.CosNaming.NameComponent;
import org.omg.CosNaming.NamingContextExt;
import org.omg.CosNaming.NamingContextExtHelper;
import org.omg.PortableServer.POA;
import org.omg.PortableServer.POAHelper;
//import org.omg.PortableServer.POAManager;

public class server {

	/** Server name, clients needs to know this name */
	public static final String SERVER_NAME = "MyServerName";

	public static void main(String [] args) {

		try {

			// Create and initialize the CORBA ORB
			ORB orb = ORB.init(args, null);
 
			// Get reference to root POA and activate the POA Manager
			POA rootpoa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
			rootpoa.the_POAManager().activate();
 
			// create servant and register it with the ORB
			MyExampleInterface_impl service = new MyExampleInterface_impl();
 
			// Get object reference from the servant
			org.omg.CORBA.Object ref = rootpoa.servant_to_reference(service);
			ExampleInterface href = ExampleInterfaceHelper.narrow(ref);
 
			// Get the root naming context
			org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
			// Use NamingContextExt which is part of the Interoperable
			// Naming Service (INS) specification.
			NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
 
			// Bind the Object Reference in naming service
			NameComponent path[] = ncRef.to_name( SERVER_NAME );
			ncRef.rebind(path, href);
 
			System.out.println("Java server '" + SERVER_NAME + "'' is running ...");
 
			// Wait for remote invocations from clients
			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);
		}
	}
}

Client

client.java

import org.omg.CORBA.ORB;
import org.omg.CosNaming.NamingContextExt;
import org.omg.CosNaming.NamingContextExtHelper;

public class client {

	/** Name is defined in the server.cpp */
	public static final String SERVER_NAME = "MyServerName";

	public static void main(String [] args) {

		try {

			// Create and initialize the CORBA ORB
			ORB orb = ORB.init(args, null);
 
			// Get the root naming context
			org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
			// Use NamingContextExt instead of NamingContext. This is 
			// Part of the Interoperable naming Service.  
			NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
 
			// Resolve the Object Reference in Naming
			ExampleInterface service_server = ExampleInterfaceHelper.narrow(ncRef.resolve_str(SERVER_NAME));

			// Use service
			System.out.println("Java client is running ...");
			String server = service_server.send_message("Message from Java client");
			System.out.println("> Response from Server: " + 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);
		}
	}
}

Build

Use the IDL compiler for JAVA idjl Generate files from the interface description example.idl

idlj -fall example.idl

idlj creates the files

  • ExampleInterface.java
  • ExampleInterfaceHelper.java
  • ExampleInterfaceHolder.java
  • ExampleInterfaceOperations.java
  • ExampleInterfacePOA.java
  • _ExampleInterfaceStub.java

Just use the java/Makefile[1] to compile the code:

# Makefile

#JAVA_HOME=/usr/lib/jvm/java-7-openjdk-i386

IDL=$(JAVA_HOME)/bin/idlj
IDLFLAGS=-fall

JAVA=java
JAVAC=javac

IDL_FILE = ../example.idl

.PHONY: all
all: server.class client.class

server.class: \
	server.java \
	MyExampleInterface_impl.java \
	ExampleInterfacePOA.java \
	ExampleInterfaceOperations.java \
	ExampleInterfaceHelper.java \
	ExampleInterface.java \
	_ExampleInterfaceStub.java
	$(JAVAC) $^

client.class: \
	client.java \
	ExampleInterface.java \
	ExampleInterfaceOperations.java \
	ExampleInterfaceHelper.java \
	_ExampleInterfaceStub.java
	$(JAVAC) $^

ExampleInterface.java ExampleInterfaceHelper.java ExampleInterfaceHolder.java ExampleInterfaceOperations.java ExampleInterfacePOA.java _ExampleInterfaceStub.java: $(IDL_FILE)
	$(IDL) $(IDLFLAGS) $<

.PHONY: clean
clean:
	find . -maxdepth 1 -type f -name "*.bak" -exec rm -f {} \;
	find . -maxdepth 1 -type f -name "*.class" -exec rm -f {} \;
	find . -maxdepth 1 -type f -name "ExampleInterface.java" -exec rm -f {} \;
	find . -maxdepth 1 -type f -name "ExampleInterfaceHelper.java" -exec rm -f {} \;
	find . -maxdepth 1 -type f -name "ExampleInterfaceHolder.java" -exec rm -f {} \;
	find . -maxdepth 1 -type f -name "ExampleInterfaceOperations.java" -exec rm -f {} \;
	find . -maxdepth 1 -type f -name "ExampleInterfacePOA.java" -exec rm -f {} \;
	find . -maxdepth 1 -type f -name "_ExampleInterfaceStub.java" -exec rm -f {} \;

Execute

  • Name Service: WIE OBEN
  • Server
java server -ORBInitRef NameService=corbaloc::localhost:4333/NameService
  • Client
java client -ORBInitRef NameService=corbaloc::localhost:4333/NameService

Errors and problems

If g++ or idlj is missing, install it (on Linux) by

sudo apt-get install g++
sudo apt-get install openjdk-7-jdk

References

  1. 1.0 1.1 Mario Konrad, mario-konrad.ch, CORBA Tutorial: Connecting 3 ORBs, online: http://www.mario-konrad.ch/wiki/doku.php?id=programming:corba:connect_orbs

See also