The interfaces necessary to “see” an internal object like a remote component are based on the definition of a “contract” that specifies the services proposed by a component and the mode of accessing these services (input and output parameters, exceptions returned).
These declarations are contained in an IDL file that is used as a reference to define the interface code at the component end and at the clients end of the component. Examples are given later. The designer of the component starts from the IDL file and develops a server end interface to set up communication between the network (through CORBA) and the internal object. The designer of each client starts from the IDL file and develops an interface to set up communication between the network (through CORBA) and the component user code.
Access from CORBA
The first step is for the component developer to define a list of proposed services and the method of calling them, in a file called the IDL file. This file contains data structures declarations and classes (“interface” in the CORBA terminology) in a language defined by the CORBA (IDL) standard. OMG IDL Syntax and Semantics [IDL] is a reference document on the IDL language syntax.
An IDL file is written to access objects (C++) in the alglin class from CORBA (see the alglin.hxx file in Example 1 and other examples). The corresponding IDL file may for example contain:
alglin.idl
module Distant {
typedef sequence<double> vecteur;
interface AlgLin
{
void addvec(out vecteur C, in vecteur A, in vecteur B);
double prdscl(in vecteur A, in vecteur B);
};
};
Comments
An IDL file is constructed to access (python) objects in the FreeFem class from CORBA (see FreeFem.py, Example 4 and subsequent examples). The corresponding IDL file may for example contain:
FreeFem.idl
module Solveur {
struct Bord {
string X;
string Y;
long n;
};
typedef sequence<Bord> seqBords;
interface FreeFem {
void Bords(in seqBords B);
void Flux(in string u1, in string u2);
void Convection(in string cond_init, in double dt, in long n);
};
};
A server end interface has to be developed from the IDL file. The principle consists of defining an object communicating firstly with the internal object and secondly with the CORBA communication layer. It will be written in a manner that will depend on the implementation language of the internal object (C++ or python).
CORBA C++ interface generation
When the internal object is written in C++ (or it has a C++ higher layer), a C++ implementation class will have to be defined at the server end that
is derived from the class of the internal objectThe first version is recommended in preference, because it is easier to implement.
Important: Most CORBA implementations can generate skeletons of implementation classes. It is strongly recommended that this feature should be used to facilitate writing implementation classes.
In the case of omniORB:
omniidl -bcxx -Wbexample <nom>.idl
(note the –Wbexample option) generates a <name>_i.cc file that contains the implementation class and an example of the main program at the server end. This file then has to be “cleaned” (keeping the method call prototypes) and completed. Methods for implementation classes receive and return CORBA objects. Therefore, if necessary, each method must:
Consider an example consisting of a server end implementation class that calls objects in the alglin class from CORBA:
alglin_i.hxx
#ifndef ALGLIN_I_ #define ALGLIN_I_ #include <alglin.hh> #include "alglin.hxx" class AlgLin_i : public POA_Distant::AlgLin, public PortableServer::RefCountServantBase { private: alglin A_interne; public: AlgLin_i(); virtual ~AlgLin_i(); void addvec(Distant::vecteur_out C, const Distant::vecteur& A, const Distant::vecteur& B); CORBA::Double prdscl(const Distant::vecteur& A, const Distant::vecteur& B); }; #endif
alglin_i.cxx
#include "alglin_i.hxx" #include <iostream> AlgLin_i::AlgLin_i() { } AlgLin_i::~AlgLin_i() { } void AlgLin_i::addvec(Distant::vecteur_out C, const Distant::vecteur& A, const Distant::vecteur& B) { long i, n = A.length(); vecteur A_(n); vecteur B_(n); vecteur C_(n); double *xA = A_.x(); double *xB = B_.x(); double *xC = C_.x(); for (i=0; i<n; i++) { xA[i] = A[i]; xB[i] = B[i]; } A_interne.addvec(&C_, &A_, &B_); C = new Distant::vecteur; C->length(n); for (i=0; i<n; i++) { (*C)[i] = xC[i]; } } CORBA::Double AlgLin_i::prdscl(const Distant::vecteur& A, const Distant::vecteur& B) { long i, n = A.length(); vecteur A_(n); vecteur B_(n); double *xA = A_.x(); double *xB = B_.x(); for (i=0; i<n; i++) { xA[i] = A[i]; xB[i] = B[i]; } return A_interne.prdscl(&A_, &B_); }
This case is similar to the previous case. It can be simpler (it is not always necessary to include input and output parameter conversion phases).
Generation of the python CORBA interface
We will consider an example consisting of the python implementation class at the server end used to call objects in the FreeFem class from CORBA:
FreeFem_i.py
import Solveur__POA
import FreeFem
class FreeFem_i(Solveur__POA.FreeFem):
def __init__(self):
self.F = FreeFem.FreeFem();
def Bords(self, b):
self.F.Bords(b);
def Flux(self, u1, u2):
self.F.Flux(u1, u2);
def Convection(self, cond_init, dt, n):
self.F.Convection(cond_init, dt, n)
The client end interface code can be written in any language (provided that there is a CORBA implementation in this language), independently of the language(s) used at the server end.
Essentially, it is necessary:
In the context of SALOME, there is no need to write clients for user components. However, consider a C++ client example and a python client example in the CORBA AlgLin class:
client.cxx
#include <CORBA.h>
#include <fstream>
#include <string>
#include "alglin.hh"
int main(int argc,char **argv)
{
CORBA::ORB_ptr orb = CORBA::ORB_init (argc, argv);
string s;
ifstream f("AlgLin.ior");
f >> s;
f.close();
CORBA::Object_ptr O = orb->string_to_object(s.c_str());
Distant::AlgLin_var A = Distant::AlgLin::_narrow(O);
long n = 5;
Distant::vecteur V1;
V1.length(n);
Distant::vecteur V2;
V2.length(n);
for (long i=0; i<n; i++) {
V1[i] = i*i;
V2[i] = 2*i;
}
CORBA::Double S = A->prdscl(V1, V2);
cerr << S << endl;
}
client.py
import CORBA
orb = CORBA.ORB_init();
f = open('AlgLin.ior');
s = f.read();
f.close();
o = orb.string_to_object(s);
import Distant
o = o._narrow(Distant.AlgLin)
v1 = [ 1, 2, 3 ]
v2 = [ 3, 4, 5 ]
v3 = o.addvec(v1, v2)
print v3
print o.prdscl(v1, v3)