在同一个应用程序/模块中使用不同的CORBA接口不兼容版本?

时间:2011-03-03 07:55:50

标签: c++ compatibility corba

给出两个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

2 个答案:

答案 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");