Использование разных несовместимых версий интерфейса 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 ответа

Решение

(Добавление ответа от одного Стефана Густафссона, опубликовано в 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, вы можете создавать любые вызовы, которые вам нравятся, и можете полностью контролировать свой клиентский код.


Я думаю, что это хорошая идея, но я пока не смог ее опробовать, поэтому могут возникнуть некоторые неожиданные сюрпризы в отношении вещей, которых больше нет в глобальном пространстве имен.

Мне приходит в голову разделение клиентского кода на отдельные библиотеки для каждой версии. Затем вы можете выбрать правильный клиент в зависимости от используемой версии. В недавнем проекте мы справились с этим, представив сервисный уровень без зависимости от 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");
Другие вопросы по тегам