Binary RPC 2 - CORBA

Content:

  1. Introduction
  2. CORBA
  3. Example
  4. Java SE
  5. .NET IIOP.NET
  6. OmniORB C++
  7. OmniORB Python

Introduction:

The article Binary RPC 1 - technology specific show binary RPC calls specific for a single technology.

Obviously it is interesting if it is possible to make binary RPC calls across different technologies.

Several such technologies exist, including:

This article will look into CORBA.

For Thrift see here.

CORBA:

CORBA (Common Object Request Broker Architecture) 1.0 was defined by OMG (Object Management Group) in 1991. CORBA 2.0 showed up in 1996 and CORBA 3.0 in 2002.

CORBA allows binary RPC calls across different technologies and programming languages.

To be technology/language neutral the interface is defined in CORBA IDL (Interface Definition Language).

Both client code (called stub) and server code (called skeleton) in one or more languages can be generated from the IDL.

Overview:

CORBA model

Two flavors exist for server side skeleton code:

The network protocol used between ORB's is genericaly called GIOP (General InterORB Protocol). In practice communication is TCP/IP based and then called IIOP (Internet InterORB Protocol).

It is possible to use CORBA without a nameserver and with a nameserver. All the examples here will use a nameserver.

Object registration in nameserver can be both transient and persistent.

Let us be clear: CORBA is old and not widely used anymore. It is probably symptomatic that Java 11 dropped CORBA support - it is not considered necessary today. But CORBA is a powerful technology once and it was 15 years ahead of its time. And it still works fine.

I do not have practical experience with CORBA so code below should just be seen as inspiration not necessarily the best code.

Example

All examples will be based on the following IDL.

test.idl:

module corbatest
{
    module common
    {
        struct Data
        {
            long iv;
            string sv;
        };
        interface Test
        {
            long add(in long a, in long b);
            string dup(in string s);
            Data process(in Data d);
            long getCounter();
            void noop();
        };
    };
};

Java SE:

Java SE has builtin CORBA support in version 1.0 - 10, but not in version 11-.

Besides the relative simple CORBA implementation builtin in Java SE, then several third party CORBA implementations for Java exist.

Generate stub and old style skeleton (BOA):

idlj -fall -oldImplBase test.idl
javac corbatest\common\*.java
jar cvf common1.jar corbatest\common\*.class

Generate stub and new style skeleton (POA):

idlj -fall test.idl
javac corbatest\common\*.java
jar cvf common2.jar corbatest\common\*.class

The idlj utility translate from IDL to Java.

Client.java:

package corbatest.client;

import java.util.Properties;
import java.util.stream.IntStream;

import org.omg.CORBA.ORB;
import org.omg.CosNaming.NameComponent;
import org.omg.CosNaming.NamingContext;
import org.omg.CosNaming.NamingContextHelper;

import corbatest.common.Data;
import corbatest.common.Test;
import corbatest.common.TestHelper;

public class Client {
    private static Test getStub(String orbhost, int orbport, String name) throws Exception {
        Properties p = new Properties();
        p.put("org.omg.CORBA.ORBClass", "com.sun.corba.se.impl.orb.ORBImpl");
        p.put("org.omg.CORBA.ORBInitialHost", orbhost);
        p.put("org.omg.CORBA.ORBInitialPort", Integer.toString(orbport));
        ORB orb = ORB.init(new String[0], p);
        NamingContext nc = NamingContextHelper.narrow(orb.resolve_initial_references("NameService"));
        return TestHelper.narrow(nc.resolve(new NameComponent[] { new NameComponent(name, "") }));
    }
    private static void testFunctional(String orbhost, int orbport, String name) throws Exception {
        Test tst = getStub(orbhost, orbport, name);
        int a = 123;
        int b = 456;
        int c = tst.add(a,  b);
        System.out.println(c);
        String s = "ABC";
        String s2 = tst.dup(s);
        System.out.println(s2);
        Data d = new Data(123, "ABC");
        Data d2 = tst.process(d);
        System.out.printf("%d %s\n", d2.iv, d2.sv);
        tst._release();
    }
    private static void testInstantiation(String orbhost, int orbport, String name) throws Exception {
        Test tst1 = getStub(orbhost, orbport, name);
        for(int i = 0; i < 2; i++) {
            int n = tst1.getCounter();
            System.out.println(n);
        }
        tst1._release();
        Test tst2 = getStub(orbhost, orbport, name);
        for(int i = 0; i < 2; i++) {
            int n = tst2.getCounter();
            System.out.println(n);
        }
        tst2._release();
    }
    private static final int REP = 100000;
    private static void testPerformance(String orbhost, int orbport, String name) throws Exception {
        Test tst = getStub(orbhost, orbport, name);
        long t1 = System.currentTimeMillis();
        IntStream.range(0, REP).parallel().forEach(i -> { tst.noop(); });
        long t2 = System.currentTimeMillis();
        System.out.printf("%d requests per second\n", REP * 1000 / (t2 - t1));
        tst._release();
    }
    private static void test(String lbl, String orbhost, int orbport, String name) throws Exception {
        System.out.println(lbl + ":");
        testFunctional(orbhost, orbport, name);
        testInstantiation(orbhost, orbport, name);
        testPerformance(orbhost, orbport, name);
    }
    private static final String JAVASE_HOST = "localhost";
    private static final int JAVASE_PORT = 1050;
    private static final String JAVASE_NAME1 = "TestJ1";
    private static final String JAVASE_NAME2 = "TestJ2";
    private static final String IIOPNET_HOST = "localhost";
    private static final int IIOPNET_PORT = 12345;
    private static final String IIOPNET_NAME = "TestN";
    private static final String OMNIORB_HOST = "localhost";
    private static final int OMNIORB_PORT = 2809;
    private static final String OMNIORB_NAME1 = "TestC1";
    private static final String OMNIORB_NAME2 = "TestC2";
    private static final String OMNIORB_NAME3 = "TestPy";
    public static void main(String[] args) throws Exception {
        test("Java SE ORB and Java Server (old style)", JAVASE_HOST, JAVASE_PORT, JAVASE_NAME1);
        test("Java SE ORB and Java Server (new style)", JAVASE_HOST, JAVASE_PORT, JAVASE_NAME2);
        test("IIOP.NET ORB and .NET Server", IIOPNET_HOST, IIOPNET_PORT, IIOPNET_NAME);
        test("OmniORB ORB and C++ Server (old style)", OMNIORB_HOST, OMNIORB_PORT, OMNIORB_NAME1);
        test("OmniORB ORB and C++ Server (new style)", OMNIORB_HOST, OMNIORB_PORT, OMNIORB_NAME2);
        test("OmniORB ORB and Python Server", OMNIORB_HOST, OMNIORB_PORT, OMNIORB_NAME3);
    }
}

TestImpl.java:

package corbatest.server;

import corbatest.common.Data;
import corbatest.common.TestPOA;;

public class TestImpl extends TestPOA {
    private int counter = 0;
    @Override
    public int add(int a, int b) {
        return a + b;
    }
    @Override
    public String dup(String s) {
        return s + s;
    }
    public Data process(Data d) {
        return new Data(d.iv + 1, d.sv + "X");
    }
    @Override
    public int getCounter() {
        counter++;
        return counter;
    }
    @Override
    public void noop() {
        // nothing
    }
}

Server.java in old style (BOA):

package corbatest.server;

import java.util.Properties;

import org.omg.CORBA.ORB;
import org.omg.CosNaming.NameComponent;
import org.omg.CosNaming.NamingContext;
import org.omg.CosNaming.NamingContextHelper;

public class Server1 {
    private static final String NAMESERVER = "localhost";
    private static final String NAMESERVER_PORT = "1050";
    private static final String NAME = "TestJ1";
    public static void main(String[] args) throws Exception {
        Properties p = new Properties();
        p.put("org.omg.CORBA.ORBClass", "com.sun.corba.se.impl.orb.ORBImpl");
        p.put("org.omg.CORBA.ORBInitialHost", NAMESERVER);
        p.put("org.omg.CORBA.ORBInitialPort", NAMESERVER_PORT);
        ORB orb = ORB.init(args, p);
        TestImpl srv = new TestImpl();
        orb.connect(srv);
        NamingContext nc = NamingContextHelper.narrow(orb.resolve_initial_references("NameService"));
        nc.rebind(new NameComponent[] { new NameComponent(NAME, "") }, srv);
        System.out.print("Press enter to exit");
        System.in.read();
        nc.unbind(new NameComponent[] { new NameComponent(NAME, "") });
        orb.disconnect(srv);
    }
}

Server.java in new style (POA):

package corbatest.server;

import java.util.Properties;

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

import corbatest.common.TestHelper;

public class Server2 {
    private static final String NAMESERVER = "localhost";
    private static final String NAMESERVER_PORT = "1050";
    private static final String NAME = "TestJ2";
    public static void main(String[] args) throws Exception {
        Properties p = new Properties();
        p.put("org.omg.CORBA.ORBClass", "com.sun.corba.se.impl.orb.ORBImpl");
        p.put("org.omg.CORBA.ORBInitialHost", NAMESERVER);
        p.put("org.omg.CORBA.ORBInitialPort", NAMESERVER_PORT);
        ORB orb = ORB.init(args, p);
        POA poa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
        poa.the_POAManager().activate();
        TestImpl srv = new TestImpl();
        NamingContextExt nc = NamingContextExtHelper.narrow(orb.resolve_initial_references("NameService"));
        nc.rebind(nc.to_name(NAME), TestHelper.narrow(poa.servant_to_reference(srv)));
        orb.run();
        //System.out.print("Press enter to exit");
        //System.in.read();
        //nc.unbind(nc.to_name(NAME));
        //orb.shutdown(false);
    }
}

Start Java SE nameserver

orbd -ORBInitialPort 1050

.NET IIOP.NET:

IIOP.NET is as open source CORBA implementation supporting .NET (C# and other .NET languages).

It is available from SourceForge.

Internally IIOP.NET is implemented on top of the .NET remoting framework (see here).

IIOP.NET is not widely used - CORBA was already declining in popularity when .NET showed up. But it works very well.

Generate stub and skeleton:

IDLToCLSCompiler common test.idl

The IDLToCLSCompiler translate from IDL to C# and build the resulting code to a .NET assembly (common.dll in this case).

client.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Channels;

using omg.org.CosNaming;

using Ch.Elca.Iiop;
using Ch.Elca.Iiop.Services;

using corbatest.common;

namespace CorbaTest.Client
{
    public class Program
    {
        private static Test GetStub(string orbhost, int orbport, string name)
        {
            NamingContext nc = CorbaInit.GetInit().GetNameService(orbhost, orbport);
            return (Test)nc.resolve(new NameComponent[] { new NameComponent(name, "") });
        }
        private static void TestFunctional(string orbhost, int orbport, string name)
        {
            Test tst = GetStub(orbhost, orbport, name);
            int a = 123;
            int b = 456;
            int c = tst.add(a,  b);
            Console.WriteLine(c);;
            String s = "ABC";
            String s2 = tst.dup(s);
            Console.WriteLine(s2);
            Data d = new Data(123, "ABC");
            Data d2 = tst.process(d);
            Console.WriteLine("{0} {1}", d2.iv, d2.sv);
        }
        private static void TestInstantiation(string orbhost, int orbport, string name) 
        {
            Test tst1 = GetStub(orbhost, orbport, name);
            for(int i = 0; i < 2; i++) 
            {
                int n = tst1.getCounter();
                Console.WriteLine(n);
            }
            Test tst2 = GetStub(orbhost, orbport, name);
            for(int i = 0; i < 2; i++)
            {
                int n = tst2.getCounter();
                Console.WriteLine(n);
            }
        }
        private const int REP = 100000;
        private static void TestPerformance(string orbhost, int orbport, string name)
        {
            Test tst = GetStub(orbhost, orbport, name);
            DateTime dt1 = DateTime.Now;
            Enumerable.Range(0, REP).AsParallel().ForAll(i => { tst.noop(); });
            DateTime dt2 = DateTime.Now;
            Console.WriteLine("{0} requests per second", (int)(REP / (dt2 - dt1).TotalSeconds));
        }
        private static void Test(string lbl, string orbhost, int orbport, string name)
        {
            Console.WriteLine(lbl + ":");
            TestFunctional(orbhost, orbport, name);
            TestInstantiation(orbhost, orbport, name);
            TestPerformance(orbhost, orbport, name);
        }
        private const string JAVASE_HOST = "localhost";
        private const int JAVASE_PORT = 1050;
        private const string JAVASE_NAME1 = "TestJ1";
        private const string JAVASE_NAME2 = "TestJ2";
        private const string IIOPNET_HOST = "localhost";
        private const int IIOPNET_PORT = 12345;
        private const string IIOPNET_NAME = "TestN";
        private const String OMNIORB_HOST = "localhost";
        private const int OMNIORB_PORT = 2809;
        private const String OMNIORB_NAME1 = "TestC1";
        private const String OMNIORB_NAME2 = "TestC2";
        private const String OMNIORB_NAME3 = "TestPy";
        public static void Main(string[] args)
        {
            ChannelServices.RegisterChannel(new IiopClientChannel(), false);
            Test("Java SE ORB and Java Server (old style)", JAVASE_HOST, JAVASE_PORT, JAVASE_NAME1);
            Test("Java SE ORB and Java Server (new style)", JAVASE_HOST, JAVASE_PORT, JAVASE_NAME2);
            Test("IIOP.NET ORB and .NET Server", IIOPNET_HOST, IIOPNET_PORT, IIOPNET_NAME);
            Test("OmniORB ORB and C++ Server (old style)", OMNIORB_HOST, OMNIORB_PORT, OMNIORB_NAME1);
            Test("OmniORB ORB and C++ Server (new style)", OMNIORB_HOST, OMNIORB_PORT, OMNIORB_NAME2);
            Test("OmniORB ORB and Python Server", OMNIORB_HOST, OMNIORB_PORT, OMNIORB_NAME3);
        }
    }
}

server.cs:

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;

using Ch.Elca.Iiop;

using corbatest.common;

namespace CorbaTest.Server
{
    public class TestImpl : MarshalByRefObject, Test
    {
        private int counter;
        public int add(int a, int b)
        {
            return a + b;      
        }
        public String dup(String s)
        {
            return s + s;    
        }
        public Data process(Data d)
        {
            return new Data(d.iv + 1, d.sv + "X");
        }
        public int getCounter()
        {
            counter++;
            return counter;        
        }
        public void noop()
        {
           // nothing    
        }
    }
    public class Program
    {
        private const int SERVER_PORT = 12345;
        private const string NAME = "TestN";
        public static void Main(string[] args)
        {
            ChannelServices.RegisterChannel(new IiopChannel(SERVER_PORT), false);
            RemotingServices.Marshal(new TestImpl(), NAME);
            Console.ReadKey();
        }
    }
}

IIOP.NET does not provide a nameserver - it is embedded in the server.

OmniORB C++:

OmniORB is a widely used open source CORBA implementation supporting C++ and Python.

It is available from SourceForge.

This is for C++.

Generate stub and skeleton:

omniidl -bcxx -Wbh=.h -Wbs=.cpp -WbBOA test.idl

The omniidl utility with -bcxx translate from IDL to C++. The -WbBOA option instruct the utility to generate both BOA and POA code. More specifically in this case it generate a test.h and test.cpp file.

client.cpp:

#include <iostream>
#include <ctime>

using namespace std;

#include "test.h"

using namespace CORBA;
using namespace CosNaming;
using namespace omniORB;

using namespace corbatest::common;

static Test_var getStub(ORB_var orb, const char *name)
{
    NamingContext_var nc = NamingContext::_narrow(orb->resolve_initial_references("NameService"));
    Name n;
    n.length(1);
    n[0].id   = (const char *)name;
    n[0].kind = (const char *)"";
    return Test::_narrow(nc->resolve(n));
}

static void testFunctional(ORB_var orb, const char *name)
{
    Test_var tst = getStub(orb, name);
    int a = 123;
    int b = 456;
    int c = tst->add(a, b);
    cout << c << endl;
    char *s = "ABC";
    char *s2 = tst->dup(s);
    cout << s2 << endl;
    Data *d = new Data();
    d->iv = 123;
    d->sv = "ABC";
    Data *d2 = tst->process(*d);
    cout << d2->iv << " " << d2->sv << endl;
}

static void testInstantiation(ORB_var orb, const char *name)
{
    Test_var tst1 = getStub(orb, name);
    for(int i = 0; i < 2; i++)
    {
        int n = tst1->getCounter();
        cout << n << endl;
    }
    Test_var tst2 = getStub(orb, name);
    for(int i = 0; i < 2; i++)
    {
        int n = tst2->getCounter();
        cout << n << endl;
    }
}

static const int REP = 100000;

static void testPerformance(ORB_var orb, const char *name)
{
    Test_var tst = getStub(orb, name);
    time_t t1 = time(NULL);
    for(int i = 0; i < REP; i++)
    {
        tst->noop();
    }
    time_t t2 = time(NULL);
    cout << (REP / (t2 - t1)) << " requests per second" << endl;
}

static void test(char *lbl, int argc, char *argv[], const char *ns, const char *name)
{
    cout << lbl << ":" << endl;
    try
    {
        const char *options[][2] = { { "InitRef", ns }, { 0, 0 } };
        ORB_var orb = ORB_init(argc, argv, "omniORB4", options);
        testFunctional(orb, name);
        testInstantiation(orb, name);
        testPerformance(orb, name);
        orb->destroy();
    }
    catch(Exception& ex)
    {
         cerr << ex._name() << endl;
    }
    catch(fatalException& fe)
    {
        cerr << fe.errmsg() << endl;
    }
    catch(...) 
    {
        cerr << "Ooops" << endl;
    }
}

static const char *JAVASE_NS = "NameService=corbaname::localhost:1050";
static const char *JAVASE_NAME1 = "TestJ1";
static const char *JAVASE_NAME2 = "TestJ2";
static const char *IIOPNET_NS = "NameService=corbaname::localhost:12345";
static const char *IIOPNET_NAME = "TestN";
static const char *OMNIORB_NS = "NameService=corbaname::localhost:2809";
static const char *OMNIORB_NAME1 = "TestC1";
static const char *OMNIORB_NAME2 = "TestC2";
static const char *OMNIORB_NAME3 = "TestPy";

int main(int argc, char *argv[])
{
    test("Java SE ORB and Java Server (old style)", argc, argv, JAVASE_NS, JAVASE_NAME1);
    test("Java SE ORB and Java Server (new style)", argc, argv, JAVASE_NS, JAVASE_NAME2);
    test("IIOP.NET ORB and .NET Server", argc, argv, IIOPNET_NS, IIOPNET_NAME);
    test("OmniORB ORB and C++ Server (old style)", argc, argv, OMNIORB_NS, OMNIORB_NAME1);
    test("OmniORB ORB and C++ Server (new style)", argc, argv, OMNIORB_NS, OMNIORB_NAME2);
    test("OmniORB ORB and Python Server", argc, argv, OMNIORB_NS, OMNIORB_NAME3);
    return 0;
}

testimpl.h for old style (BOA):

#include "test.h"

using namespace CORBA;
using namespace corbatest::common;

class TestImpl : public _sk_Test
{
private:
    int counter;
public:
    TestImpl() { counter = 0; }
    virtual ~TestImpl() { }
    virtual Long add(Long a, Long b);
    virtual char *dup(const char *s);
    virtual Data* process(const Data& d);
    virtual Long getCounter();
    virtual void noop();
};

The point is that it extends corbatest::common::_sk_Test.

testimpl.h for new style (POA):

#include "test.h"

using namespace CORBA;
using namespace corbatest::common;

class TestImpl : public POA_corbatest::common::Test
{
private:
    int counter;
public:
    TestImpl() { counter = 0; }
    virtual ~TestImpl() { }
    virtual Long add(Long a, Long b);
    virtual char *dup(const char *s);
    virtual Data* process(const Data& d);
    virtual Long getCounter();
    virtual void noop();
};

The point is that it extends POA_corbatest::common::Test.

testimpl.cpp:

#include <cstring>

using namespace std;

#include "testimpl.h"

Long TestImpl::add(Long a, Long b)
{
    return a + b;
}

char *TestImpl::dup(const char *s)
{
    char *res = new char[2 * strlen(s) + 1];
    strcpy(res, s);
    strcat(res, s);
    return res;
}

Data *TestImpl::process(const Data& d)
{
    Data *res = new Data();
    res->iv = d.iv + 1;
    char *temp = new char[strlen(d.sv) + 2];
    strcpy(temp, d.sv);
    strcat(temp, "X");
    res->sv = temp;
    return res;
}

Long TestImpl::getCounter()
{
    counter++;
    return counter;
}

void TestImpl::noop()
{
    // nothing
}

server.cpp in old style (BOA):

#include <iostream>

using namespace std;

#include "test.h"
#include "testimpl.h"

using namespace CORBA;
using namespace CosNaming;
using namespace PortableServer;
using namespace omniORB;

using namespace corbatest::common;

static const char *NS = "NameService=corbaname::localhost:2809";
static const char *NAME = "TestC1";

int main(int argc, char *argv[])
{
    try
    {
        const char *options[][2] = { { "InitRef", NS }, { 0, 0 } };
        ORB_var orb = ORB_init(argc, argv, "omniORB4", options);
        BOA_var boa = orb->BOA_init(argc, argv, "omniORB4_BOA");
        TestImpl *srv = new TestImpl();
        srv->_obj_is_ready(boa);
        NamingContext_var nc = NamingContext::_narrow(orb->resolve_initial_references("NameService"));
        Name n;
        n.length(1);
        n[0].id   = (const char *)NAME;
        n[0].kind = (const char *)"";
        try
        {
            nc->bind(n, srv->_this());
        }
        catch(NamingContext::AlreadyBound& ex)
        {
            nc->rebind(n, srv->_this());
        }
        boa->impl_is_ready();
        //puts("Press enter to exit");
        //getchar();
        //nc->unbind(n);
        //boa->destroy();
        //orb->destroy();
    }
    catch(Exception& ex)
    {
         cerr << ex._name() << endl;
    }
    catch(fatalException& fe)
    {
        cerr << fe.errmsg() << endl;
    }
    catch(...) 
    {
        cerr << "Ooops" << endl;
    }
    return 0;
}

server.cpp in new style (POA):

#include <iostream>

using namespace std;

#include "test.h"
#include "testimpl.h"

using namespace CORBA;
using namespace CosNaming;
using namespace PortableServer;
using namespace omniORB;

using namespace corbatest::common;

static const char *NS = "NameService=corbaname::localhost:2809";
static const char *NAME = "TestC2";

int main(int argc, char *argv[])
{
    try
    {
        const char *options[][2] = { { "InitRef", NS }, { 0, 0 } };
        ORB_var orb = ORB_init(argc, argv, "omniORB4", options);
        POA_var poa = POA::_narrow(orb->resolve_initial_references("RootPOA"));
        Servant_var<TestImpl> srv = new TestImpl();
        poa->activate_object(srv);
        NamingContext_var nc = NamingContext::_narrow(orb->resolve_initial_references("NameService"));
        Name n;
        n.length(1);
        n[0].id   = (const char *)NAME;
        n[0].kind = (const char *)"";
        try
        {
            nc->bind(n, srv->_this());
        }
        catch(NamingContext::AlreadyBound& ex)
        {
            nc->rebind(n, srv->_this());
        }
        POAManager_var poaman = poa->the_POAManager();
        poaman->activate();
        orb->run();
        //puts("Press enter to exit");
        //getchar();
        //nc->unbind(n);
        //orb->destroy();
    }
    catch(Exception& ex)
    {
         cerr << ex._name() << endl;
    }
    catch(fatalException& fe)
    {
        cerr << fe.errmsg() << endl;
    }
    catch(...) 
    {
        cerr << "Ooops" << endl;
    }
    return 0;
}

Start OmniORB nameserver

omniNames -start 2809 -logdir . -ORBsupportBootstrapAgent 1

The option -ORBsupportBootstrapAgent 1 is necessary to make it work with Java SE.

OmniORB Python:

OmniORB is a widely used open source CORBA implementation supporting C++ and Python.

It is available from SourceForge.

This is for Python.

Generate stub and skeleton:

omniidl -bpython test.idl

The omniidl utility with -bpython translate from IDL to Python.

client.py:

import sys
import time

sys.path.append('C:\\DivNative\\64bit\\omniORBpy-4.2.2-2.7\\lib\\python')
sys.path.append('C:\\DivNative\\64bit\\omniORBpy-4.2.2-2.7\\lib\\x86_win32')

from omniORB import CORBA
import CosNaming

import corbatest.common

def getStub(orb, name):
    nc = orb.resolve_initial_references('NameService')._narrow(CosNaming.NamingContext)
    n = [CosNaming.NameComponent(name, '')]
    return nc.resolve(n)._narrow(corbatest.common.Test)

def testFunctional(orb, name):
    tst = getStub(orb, name)
    a = 123
    b = 456
    c = tst.add(a, b)
    print(str(c))
    s = 'ABC'
    s2 = tst.dup(s)
    print(s2)
    d = corbatest.common.Data(123, 'ABC')
    d2 = tst.process(d)
    print('%d %s' % (d2.iv,d2.sv))

def testInstantiation(orb, name):
    tst1 = getStub(orb, name)
    for i in range(0, 2):
        n = tst1.getCounter()
        print(str(n))
    tst2 = getStub(orb, name)
    for i in range(0, 2):
        n = tst2.getCounter()
        print(str(n))

def testPerformance(orb, name):
    tst = getStub(orb, name)
    REP = 10000
    t1 = time.time()
    for i in range(0, REP):
        tst.noop()
    t2 = time.time()
    print('%d requests per second' % (REP / (t2 - t1)))

def test(lbl, ns, name):
    print(lbl + ':')
    orb = CORBA.ORB_init(['-ORBInitRef', ns], CORBA.ORB_ID)
    testFunctional(orb, name)
    testInstantiation(orb, name)
    testPerformance(orb, name)
    orb.destroy()

test('Java SE ORB and Java Server (old style)', 'NameService=corbaname::localhost:1050', 'TestJ1')
test('Java SE ORB and Java Server (new style)', 'NameService=corbaname::localhost:1050', 'TestJ2')
test('IIOP.NET ORB and .NET Server', 'NameService=corbaname::localhost:12345', 'TestN')
test('OmniORB ORB and C++ Server (old style)', 'NameService=corbaname::localhost:2809', 'TestC1')
test('OmniORB ORB and C++ Server (new style)', 'NameService=corbaname::localhost:2809', 'TestC2')
test('OmniORB ORB and Python Server', 'NameService=corbaname::localhost:2809', 'TestPy')

server.py:

import sys
import time

sys.path.append('C:\\DivNative\\64bit\\omniORBpy-4.2.2-2.7\\lib\\python')
sys.path.append('C:\\DivNative\\64bit\\omniORBpy-4.2.2-2.7\\lib\\x86_win32')

from omniORB import CORBA
from omniORB import PortableServer
import CosNaming

import corbatest.common
import corbatest__POA.common

class TestImpl(corbatest__POA.common.Test):
    def __init__(self):
        self.counter = 0
    def add(self,a,b):
        return a + b
    def dup(self,s):
        return s + s
    def process(self,d):
        return corbatest.common.Data(d.iv + 1, d.sv + 'X')
    def getCounter(self):
        self.counter = self.counter + 1
        return self.counter
    def noop(self):
        return
    
orb = CORBA.ORB_init(['-ORBInitRef', 'NameService=corbaname::localhost:2809'], CORBA.ORB_ID)
poa = orb.resolve_initial_references('RootPOA')
srv = TestImpl()
nc = orb.resolve_initial_references('NameService')._narrow(CosNaming.NamingContext)
n = [CosNaming.NameComponent('TestPy', "")]
try:
    nc.bind(n, srv._this())
except CosNaming.NamingContext.AlreadyBound:
    nc.rebind(n, srv._this())
poaman = poa._get_the_POAManager()
poaman.activate()
orb.run()
#nc.ubind(n)
#orb.destroy()

OmniORB for Python actually supports both BOA and POA, but I am showing only POA as I expect all Python code to use that.

Start OmniORB nameserver

omniNames -start 2809 -logdir . -ORBsupportBootstrapAgent 1

The option -ORBsupportBootstrapAgent 1 is necessary to make it work with Java SE.

Article history:

Version Date Description
1.0 November 11th 2018 Initial version

Other articles:

See list of all articles here

Comments:

Please send comments to Arne Vajhøj