给出两个IDL定义:(我只实现了一个客户端,服务器端是固定的。)
// 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();
// ...
}
};
(编辑注意:添加了无法重载的Foo3方法,因为返回类型已更改。)
是否有可能在同一个C ++ CORBA客户端应用程序中编译两个存根代码文件?
使用IDL编译器的默认值,上述两个IDL定义将导致无法编译到同一C ++模块中的存根代码,因为您会从链接器中获得多个定义错误。然而,客户端需要能够与两个服务器版本通信。
有哪些可行的解决方案?
(注意:我们正在使用omniORB)
答案 0 :(得分:2)
(添加一位Stefan Gustafsson的答案,发布于comp.object.corba 2011-03-08)
如果你把它看成是一个C ++问题而不是CORBA问题,那么 解决方案是C ++命名空间。 您可以尝试将不同的实现包装在不同的C ++中 命名空间。 像:
namespace v1 {
#include "v1/foo.h" // From foo.idl version 1
}
namespace v2 {
#include "v2/foo.h" // from foo.idl version 2
}
为了能够编译C ++代理/存根代码,您需要创建C ++ 主要文件如:
// foo.cpp
namespace v1 {
#include "v1/foo_proxy.cpp" // filename depend on IDL compiler
}
namespace v2 {
#include "v2/foo_proxy.cpp"
}
这将阻止C ++链接器抱怨,因为名称将是 不同。你当然知道 可能会遇到不支持嵌套的C ++编译器的问题 命名空间..
第二个解决方案是使用
DII
来实现调用 写一个C ++类
class ServerCall {
void foo2_v1() {
// create request
// invoke
}
void foo2_v2(String arg) {
// create_list
// add_value("x",value,ARG_IN)
// create_request
// invoke
}
}
通过使用DII,您可以创建任何您喜欢的调用,并且可以保持完整 控制您的客户代码。
我认为这是一个好主意,但我还没有尝试过,所以可能会发现一些意想不到的惊喜,而不再是全局命名空间中的事情。
答案 1 :(得分:1)
我想到的是将客户端代码拆分为每个版本的单独库。 然后,您可以根据要使用的版本选择正确的客户端。 在最近的一个项目中,我们通过引入一个不依赖于CORBA IDL的服务层来处理这个问题。 例如:
class ObjectService
{
public:
virtual void Foo1() = 0;
virtual void Foo2() = 0;
virtual void Foo2(const std::string &x) = 0;
};
对于每个版本,创建一个派生自ObjectService的类并通过执行操作 调用CORBA :: Object。每个派生类必须位于单独的库中。
在客户端实现中,您只对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");