CORBA
The Common Object Request Broker Architecture is a middleware system for
building distributed applications. It is looked after by the Object Management
Group (OMG) which has been in existence for about 10 years.
CORBA supports distributed objects. The "objects" may be written
in C, C++, Ada, Java, SmallTalk, Python, etc. Some of these are not O/O
languages. A single distributed application may use a mixture of languages.
Objects communicate by making method calls on one another. The CORBA
"backplane" or Object Request Broker (ORB) looks after marshalling
parameters, transferring the data, making the remote call and returning the
results.

The ORB structure is

Objects may be located in a variety of ways. These include
- Portable
"string-ified" references
- Naming service
- Trader service
CORBA IDL
To achieve language independence, CORBA applications are specified by interfaces
written in an IDL (Interface Definition Language). CORBA IDL is different to
Sun's RPC/ONC IDL and to DCE IDL. It is based on C++, with changes to
accomodate distributed objects, such as in/out parameters instead of
reference/value parameters.
A simple IDL is
module HelloApp { interface Hello { string sayHello();
};
};
A more complex one is
module RoomBooking {
interface Meeting { readonly attribute string purpose;
readonly attribute string participants;
oneway void destroy();
};
interface MeetingFactory { Meeting CreateMeeting(in string purpose, in string participants);
};
enum Slot {am9, am10, am11, pm12, pm1, pm2, pm3, pm4};
const short MaxSlots = 8;
exception NoMeetingInThisSlot {}; exception SlotAlreadyTaken {};
interface Room { typedef Meeting Meetings[MaxSlots];
readonly attribute string name;
Meetings View();
void Book(in Slot a_slot, in Meeting a_meeting)
raises(SlotAlreadyTaken);
void Cancel(in Slot a_slot)
raises(NoMeetingInThisSlot);
};
};
The IDL is used to generate stubs and skeletons for the client and server.

Primitive types
|
short
|
16 bits signed
|
|
unsigned short
|
16 bits unsigned
|
|
long
|
32 bits signed
|
|
unsigned long
|
32 bits unsigned
|
|
long long
|
64 bits signed
|
|
unsigned long long
|
64 bits unsigned
|
|
char
|
8 bits
|
|
wchar
|
"wide enough" char
|
|
boolean
|
|
|
octet
|
8 bits
|
|
any
|
|
There are mappings defined to types in all of the CORBA supported languages
|
IDL
|
C/C++ (no name
spaces)
|
C++ (with
namespaces)
|
Java
|
|
short
|
CORBA_Short
|
CORBA::Short
|
short
|
|
unsigned short
|
CORBA_UShort
|
CORBA::UShort
|
short
|
|
long
|
CORBA_Long
|
CORBA::Long
|
int
|
|
unsigned long
|
CORBA_ULong
|
CORBA::ULong
|
int
|
|
long long
|
CORBA_LongLong
|
CORBA::LongLong
|
long
|
|
unsigned long long
|
CORBA_ULongLong
|
CORBA::ULongLong
|
long
|
|
char
|
CORBA_Char
|
CORBA::Char
|
char
|
|
wchar
|
CORBA_WChar
|
CORBA::WChar
|
char
|
|
boolean
|
CORBA_Boolean
|
CORBA::Boolean
|
boolean
|
|
octet
|
CORBA_Octet
|
CORBA::Octet
|
byte
|
Modules and Interfaces
An appplication may be made up from specifications from different sources.
There may be a possibility of name clashes. CORBA uses "modules" to
create separate "name spaces" so that the possibility of clashes is
reduced.
e.g.
module a { module b { ...
};
};
Classes are defined by "interfaces". For example,
module gui { interface pushButton { ...
};
interface textArea { ...
};
};
C++ mapping
C++ is still evolving. There are a number of possible mappings, depending on
which version of the language/which compiler you target.
- C++ with namespaces: the
modules form namespaces, the interfaces form classes. e.g.
· namespace gui {· class pushButton {...};· };
and the class is referenced by
gui::pushButton
- C++ without namespaces but
with nested (inner) classes gives modules as classes and interfaces as
inner classes
- C++ with neither concatenates
the module name(s) with the interface name
· class gui_pushButton {...};
This is the most portable in terms of working with the
largest number of C++ compilers, but fails to use the newer features of C++
Java mapping
Modules map to Java packages. Interfaces map to Java interfaces
package gui;
public interface pushButton { ...
};
Inheritance
IDL supports multiple inheritance of interfaces
interface Rectangle: Shape {...};
These map directly onto the inheritance mechanisms of
classes for C++ and interfaces for Java.
C++:
class Rectangle: Shape {...};
Java
interface Rectangle extends Shape {...};
Attributes
Attributes are fields of objects. They may be readonly or read/write fields.
e.g.
attribute long x;
readonly attribute long y;
Mapping to C++
Attributes are hidden. They are accessible by "set" and
"get" methods
CORBA_Long x(); // get
void x(CORBA_Long); // set
CORBA_Long y(); // get only
Mapping to Java
Attributes map to protected fields of objects. There are "set" and
"get" methods for attributes that are both readable and writable, but
only "get" methods for readonly attributes.
Java Beans (and most style guides) use getX() and setX() methods
to access an attribute. CORBA doesn't follow this. It uses X() for get
methods and X(...)
for set methods
int x(); // get
void x(int i); // set
int y(); // get only
Operations
CORBA uses the word operation for methods. These translate into operations
in C++ and methods in Java. Parameters can be in, inout or out. in parameters
translate according to the earlier tables and are passed by value. inout and out parameters
translate differently because they have to carry return values
mapping to C++
Each out
or inout
basic type maps to a CORBA type followed by _out
|
short
|
CORBA_Short_out
|
|
long
|
CORBA_Long_out
|
|
boolean
|
CORBA_Boolean_out
|
In addition, each of these is typedef'ed to a reference to
the corresponding CORBA type
typedef CORBA_Short& CORBA_Short_out;
e.g.
long f(in short x, out short y, inout short z);
maps to
virtual CORBA_Long f(CORBA_Short x,
CORBA_Short& y,
CORBA_Short& z);
Mapping to Java
Java has a set of "helper" classes such as org.omg.CORBA.ShortHolder.
These have a field value.
An instance of these classes can be passed as an out parameter, and its value field
can be changed
public int
f(short x,
org.omg.CORBA.ShortHolder y,
org.omg.CORBA.ShortHolder z);
Similar helper classes are defined for non-primitive types (objects).
CORBA and C++
Idl compiler
Given an IDL file X.idl,
an "idl to C++" compiler will generate 4 files
- a header file
X.h of
client-side type definitions
- a header file
X_skel.h
of server-side definitions
- an implementation file
X.cpp
used by both client and server
- a server skeleton
X_skel.cpp
for the server to inherit
e.g. Hello.idl
results in
Hello.h
hello_skel.h
Hello.cpp
Hello_skel.cpp
Simple C++ Client
The client is an application starting from main(). The pseudocode is
initialize CORBA ORB
find a reference to the service
cast the service to the right type
call methods on the service
For the IDL
interface Hello { void sayHello();
};
the client can use the method
void sayHello();
The client is
// for Orbacus
#include <OB/CORBA.h>
#include "Hello.h"
#include <fstream.h>
int main(int argc, char **argv)
{ // initialize CORBA ORB
CORBA_ORB_var orb = CORBA_ORB_init(argc, argv);
// find service - here pick a string form out of a file
const char* refFile = "Hello.ref";
ifstream in(refFile);
char s[1000]; // must be big enough!
in >> s;
CORBA_Object_var obj = orb -> string_to_object(s);
// cast to right type
Hello_var hello = Hello::_narrow(obj);
// invoke methods
// NB: Prints on the server!
hello -> sayHello();
exit(0);
}
Simple C++ Server
Much of the server code is supplied by the IDL compiler and the CORBA
library calls. Pseudocode for a server is
initialize CORBA ORB
initialize the BOA (Basic Object Adapter)
create a reference to the service
export the reference (so clients can find it)
enter client request loop
For the hello example, the server is
// Orbacus server
#include <OB/CORBA.h>
#include <Hello_impl.h>
#include <fstream.h>
int main(int argc, char** argv)
{ // initialize CORBA ORB
CORBA_ORB_var orb = CORBA_ORB_init(argc, argv);
// initialize the BOA
CORBA_BOA_var boa = orb -> BOA_init(argc, argv);
// create a reference to the service
Hello_var p = new Hello_impl;
// export the reference
CORBA_String_var s = orb -> object_to_string(p);
const char* refFile = "Hello.ref";
ofstream out(refFile);
out << s << endl;
out.close();
// enter client request loop
boa -> impl_is_ready(CORBA_ImplementationDef::_nil());
}
The Hello_impl
class is defined in two files: a header file and an implementation file. The
header file Hello_impl.h
is
#include <Hello_skel.h>
class Hello_impl: public Hello_skel
{ public:
virtual void sayHello();
};
and the implementation file Hello_impl.cpp is
// Orbacus
#include <OB/CORBA.h>
#include <Hello_impl.h>
void Hello_impl::sayHello()
{ cout << "Hello world" << endl;
}
CORBA and Java
Idl compiler
Given an IDL file Hello.idl,
an "idl to Java" compiler will generate 5 files
Hello.java - interface
definition in Java
HelloHelper.java - used on
the client for "type casting"
HelloHolder.java - used
for out and inout parameters
StubForHello.java -
client-side stub
_HelloImplBase.java -
server-side implementation inherits from this
(If no module name is specified, Orbacus places these in the
Java package defaultpkg).
From the Hello.idl
interface Hello { void sayHello();
};
the Java interface Hello.java is generated
package defaultpkg;
public interface Hello extends org.omg.CORBA.Object
{ public void sayHello();
}
Simple Java client
The client starts from main(),
and obtains a reference to a CORBA Object. It does this by reading the
string version of the object from a file, like the C++ case. It then casts it
to an implementation of the Hello interface.
import java.io.*;
public class JClient {
public static void main(String[] argv) { // Setup info about the CORBA implementation used
java.util.Properties props = System.getProperties();
props.put("org.omg.CORBA.ORBClass", "com.ooc.CORBA.ORB"); props.put("org.omg.CORBA.ORBSingletonClass", "com.ooc.CORBA.ORBSingleton");
System.setProperties(props);
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(argv, props);
// get object reference in string form
String ref = null;
try { String refFile = "Hello.ref";
BufferedReader in = new BufferedReader(new FileReader(refFile));
ref = in.readLine();
} catch(IOException e) { System.out.println("Cant read from file"); System.exit(1);
}
// convert to CORBA object
org.omg.CORBA.Object obj = orb.string_to_object(ref);
// convert to Hello object
defaultpkg.Hello p = defaultpkg.HelloHelper.narrow(obj);
// call methods
p.sayHello();
}
}
Simple Java server
The implementation of the service is
public class Hello_impl extends defaultpkg._HelloImplBase {
public void sayHello() { System.out.println("Hello World"); }
}
The server is
import java.io.*;
public class JServer {
static public void main(String[] argv) { // setup info about CORBA implementation
java.util.Properties props = System.getProperties();
props.put("org.omg.CORBA.ORBClass", "com.ooc.CORBA.ORB"); props.put("org.omg.CORBA.ORBSingletonClass", "com.ooc.CORBA.ORBSingleton");
System.setProperties(props);
// initialise ORB and BOA
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(argv, props);
org.omg.CORBA.BOA boa = ((com.ooc.CORBA.ORB) orb).BOA_init(argv,props);
// create CORBA object
Hello_impl helloRef = new Hello_impl();
// save string reference in file
try { String ref = orb.object_to_string(helloRef);
String refFile = "Hello.ref";
PrintWriter out = new PrintWriter(new FileOutputStream(refFile));
out.println(ref);
out.flush();
} catch(IOException e) { System.out.println("Cant write to file"); System.exit(1);
}
// server loop
boa.impl_is_ready(null);
}
}
Getting object references
Strings
The methods object_to_string()
and string_to_object()
can be used to store references to objects outside of a server so that clients
can reconstruct them. These "stringified" references are portable to
other machines - they contain location information about the service. For
example
- The stringified reference may
be stored in a file accessible to both server and clients
- The reference may form the
contents of a Web page, so that it can be fetched as a URL
- The reference may be given as
an applet parameter on a Web page, so that an applet can access the object
Naming service
A naming service is a process running independently of any other clients and
servers. A service will register itself with the naming service, passing both a
simple string as its name and an object reference to itself. A client will then
ask the naming service for the service by using its name, and will get back an
object reference.
All servers and clients will need to know the location of the naming service
in order to find it and then register/query it. This is typically done by
giving a port number or URL. e.g.
Client -ORBDefaultInitRef iioploc://pandonia:5000
for a Naming Service running on pandonia on
port 5000.
C++ resolution
The Naming Service is found by the following C++ code
CORBA_Object_var obj;
CosNaming_NamingContext_var ctx;
obj = orb -> resolve_initial_references("NameService");ctx = CosNaming_NamingContext::_narrow(obj);
C++ service
C++ client
Java resolution
The Naming Service is found this way in Java
org.omg.CORBA.Object obj;
org.omg.CosNaming.NamingContext ctx;
obj = orb.resolve_initial_references("NameService");ctx = org.omg.CosNaming.NamingContextHelper.narrow(obj);
Java service
The service registers itself with the naming service by
// bind the Hello service to the name server
NameComponent nc = new NameComponent("Hello", "");NameComponent path[] = {nc};ctx.rebind(path, helloRef);
The Java Hello
service using this is
import java.io.*;
import org.omg.CosNaming.*;
public class JServer {
static public void main(String[] argv) { java.util.Properties props = System.getProperties();
props.put("org.omg.CORBA.ORBClass", "com.ooc.CORBA.ORB"); props.put("org.omg.CORBA.ORBSingletonClass", "com.ooc.CORBA.ORBSingleton");
System.setProperties(props);
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(argv, props);
org.omg.CORBA.BOA boa = ((com.ooc.CORBA.ORB) orb).BOA_init(argv,props);
Hello_impl helloRef = new Hello_impl();
// find the naming service
org.omg.CORBA.Object obj = null;
org.omg.CosNaming.NamingContext ctx;
try { obj = orb.resolve_initial_references("NameService"); } catch(org.omg.CORBA.ORBPackage.InvalidName e) { e.printStackTrace();
System.exit(1);
}
ctx = org.omg.CosNaming.NamingContextHelper.narrow(obj);
// bind the Hello service to the naming service
NameComponent nc = new NameComponent("Hello", ""); NameComponent path[] = {nc}; try { ctx.rebind(path, helloRef);
} catch(Exception e) { e.printStackTrace();
System.exit(1);
}
boa.impl_is_ready(null);
}
}
Java client
The client uses the Naming Service to get a reference to the Hello object by
NameComponent nc = new NameComponent("Hello", "");NameComponent path[] = {nc};org.omg.CORBA.Object obj = ctx.resolve(path);
Hello helloRef = HelloHelper.narrow(obj);
The Hello
client using this is
import java.io.*;
import org.omg.CosNaming.*;
public class JClient {
public static void main(String[] argv) { java.util.Properties props = System.getProperties();
props.put("org.omg.CORBA.ORBClass", "com.ooc.CORBA.ORB"); props.put("org.omg.CORBA.ORBSingletonClass", "com.ooc.CORBA.ORBSingleton");
System.setProperties(props);
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(argv, props);
// find the naming service
org.omg.CORBA.Object obj = null;
org.omg.CosNaming.NamingContext ctx;
try { obj = orb.resolve_initial_references("NameService"); } catch(org.omg.CORBA.ORBPackage.InvalidName e) { e.printStackTrace();
System.exit(1);
}
ctx = org.omg.CosNaming.NamingContextHelper.narrow(obj);
// find the object reference
NameComponent nc = new NameComponent("Hello", ""); NameComponent path[] = {nc}; org.omg.CORBA.Object helloObj = null;
try { helloObj = ctx.resolve(path);
} catch(Exception e) { e.printStackTrace();
System.exit(1);
}
defaultpkg.Hello helloRef = defaultpkg.HelloHelper.narrow(helloObj);
helloRef.sayHello();
}
}
Running with a Naming Service
The Naming Service needs to be started on a particular machine, listening on
a particular port. e.g. for the Orbacus service
nameserv -OAport 5000
The Naming Service can be specified portably in a variety of ways. One is to
store its address in URL form in a configuration file which is copied to all clients
and services. With everything running locally, the file orb.cfg could
be
ooc.service.NameService=iioploc://localhost:5000/NameService
The client and server then run as
java JClient -ORBconfig orb.cfg
and
java JServer -ORBconfig orb.cfg