Reputation: 38785
Given two IDL definitions: (I'm only implementing a client, the server side is fixed.)
// Version 1.2
module Server {
interface IObject {
void Foo1();
void Foo2() raises(EFail);
string Foo3();
// ...
}
};
// Version 2.3
module Server {
interface IObject {
// no longer available: void Foo1();
void Foo2(string x) raises(ENotFound, EFail); // incompatible change
wstring Foo3();
// ...
}
};
(Edit Note: added Foo3 method that cannot be overloaded because the return type changed.)
Is it somehow possible to compile both stub code files in the same C++ CORBA Client App?
Using the defaults of an IDL compiler, the above two IDL definitions will result in stub code that cannot be compiled into the same C++ module, as you'd get multiple definition errors from the linker. The client however needs to be able to talk to both server versions.
What are possible solutions?
(Note: We're using omniORB)
Upvotes: 1
Views: 546
Reputation: 38785
(Adding answer from one Stefan Gustafsson, posted in comp.object.corba 2011-03-08)
If you look at it as a C++ problem instead of a CORBA problem, the solution is C++ namespaces. You could try to wrap the different implementations in different C++ namespaces. Like:
namespace v1 {
#include "v1/foo.h" // From foo.idl version 1
}
namespace v2 {
#include "v2/foo.h" // from foo.idl version 2
}
And to be able to compile the C++ proxy/stub code you need to create C++ main files like:
// foo.cpp
namespace v1 {
#include "v1/foo_proxy.cpp" // filename depend on IDL compiler
}
namespace v2 {
#include "v2/foo_proxy.cpp"
}
This will prevent the C++ linker complaining since the names will be different. Of course you could run into problems with C++ compilers not supporting nested namespaces..
A second solution is to implement the invocation using
DII
, you could write a C++ class
class ServerCall {
void foo2_v1() {
// create request
// invoke
}
void foo2_v2(String arg) {
// create_list
// add_value("x",value,ARG_IN)
// create_request
// invoke
}
}
By using DII you can create any invocation you like, and can keep full control of your client code.
I think this is a good idea, but I haven't been able to try it out yet, so there may lurk some unexpected surprises wrt to things no longer being in the global namespace.
Upvotes: 2
Reputation: 1139
What comes to my mind would be splitting the client code into separate libraries for each version. Then you can select the correct client depending on the version to be used. In a recent project we handled this by introducing a service layer with no dependency to the CORBA IDL. For example:
class ObjectService
{
public:
virtual void Foo1() = 0;
virtual void Foo2() = 0;
virtual void Foo2(const std::string &x) = 0;
};
For each version, create a class derived from ObjectService and implement the operations by calling the CORBA::Object. Each derived class must be in separate library.
In the client implementation, you only operate on instances of ObjectService.
CORBA::Object_var remoteObject=... // How to get the remote object depends on your project
ObjectService *serviceObject=0;
// create a service object matching the remote object version
// Again, this is project specific
switch (getRemoteObjectVersion(remoteObject))
{
case VERSION_1_2:
serviceObject=new ServiceObjectImpl12(remoteObject);
break;
case VERSION_2_3:
serviceObject=new ServiceObjectImpl23(remoteObject);
break;
default:
// No matching version found, throw exception?
break;
}
// Access remote object through service object
serviceObject->Foo2("42");
Upvotes: 1