问题描述
我正在使用 IDL 为使用 OpenDDS 的应用程序定义数据。
我也想使用 IDL 来定义应用程序的接口,但 OpenDDS(和大多数其他 DDS 实现)不支持 IDL 中的接口。
是否有任何编译器可以从 IDL 接口生成简单的存根?我需要它至少支持 C++ 和 Java。
作为 CORBA ORB 一部分的所有 IDL 编译器都会生成大量特定于 CORBA 的代码和样板。我想要一些从 IDL 到 C++/Java/etc 的简单映射。例如,如果我有这个 IDL:
module sample_module {
interface sample_interface {
attribute char sample_field;
boolean sample_func();
};
};
namespace sample_module {
class sample_interface {
char sample_field;
boolean sample_func();
};
};
解决方法
在 DDS 规范的 IDL 中的接口之外,据我所知,DDS 本身并没有使用接口。它总是将自己的 IDL 限制为 CORBA 的一个子集。因此,除了使用 tao_idl
已经附带的支持之外,OpenDDS 不支持用户定义的接口。可以由 opendds_idl
生成的可选 C++11 映射没有您想要的所有 CORBA 样板,但它目前不支持接口。我认为 Java 映射仅支持 OpenDDS 基于 JNI 的特定情况。即使使用 TAO 的 C++ 映射,OpenDDS 也不支持使用 interface
类型作为 DDS 主题类型或内部。
我不能像对 OpenDDS 那样多说其他 DDS 实现,但我知道 this support page for Connext 说它们也不支持接口。它确实说他们支持 valuetype
,这有点像 interface
,但他们将其视为 struct
并忽略对它们的操作。
您可以使用 local interface
支持,这会生成带有纯虚拟方法的 C++ 基类来实现。例如,这被 LwCCM 用于定义组件,例如参见 AXCIOMA,我们使用本地接口与 IDL 中定义的数据相结合。有关更多信息,请参阅我们的 articles 之一。
作为替代方案,您也可以基于 IDL 创建自己的自定义生成,在 TAOX11/AXCIOMA/R2CORBA 中,我们使用的是 RIDL,您可以创建自定义后端生成一些特定于接口的代码
,有一个名为 Remote Procedure Call over DDS(RPC over DDS)的 OMG 标准,它定义了 IDL 接口如何映射到代码(它属于 DDS 标准系列)。 CoreDX DDS 确实为多种目标语言(包括 C++、Java 和 C#)支持此标准。
除了简单地将接口映射到目标语言之外,RPC over DDS 标准还提供了一种使用 DDS 作为 RPC 操作的底层传输的方法。它提供低级接口(即手动处理发送接收请求)和高级(调用“接口”方法)API。在任何一种情况下,进程间通信都是通过 DDS 以可互操作的方式处理的。在我看来,这是一种非常强大的方法。
以下是一些 IDL 示例:
module robot {
exception TooFast {};
enum Command { START_COMMAND,STOP_COMMAND,TERMINATE_COMMAND };
struct Status
{
string msg;
};
@DDSService
interface RobotControl
{
void command(Command com);
float setSpeed(float speed) raises (TooFast);
float getSpeed();
void getStatus(out Status status);
};
};
注意:“@DDSService”注释通知有意识的 IDL 编译器为接口生成 RPC over DDS 支持。
如果没有@DDSService 注释,我们的代码生成器将简单地生成一个类声明[我认为您正在寻找],如下所示:
class RobotControl {
public:
RobotControl();
~RobotControl();
public:
virtual void command (
/* IN */ const enum robot::Command com ) = 0;
virtual float setSpeed (
/* IN */ const float speed ) = 0;
virtual float getSpeed ( ) = 0;
virtual void getStatus (
/* OUT */ struct robot::Status & status ) = 0;
};
通过@DDSService 注释,生成了更多代码,提供完整的客户端实现 (robot.RobotControlClient) 和准备实现的抽象服务器端 (robot.RobotControlService)。有了它,您的客户端应用程序可以简单地执行以下操作:
RobotControlClient robotClient = new RobotControlClient( client_params );
robotClient.setSped( 10 );
服务器应用程序可以扩展robot.RobotControlService,并实现服务调用,如下所示:
public class MyRobotControlService extends RobotControlService {
....
private static final float MAX_SPEED = (float)20.0;
public float
setSpeed ( /* in */ float speed ) throws TooFast
{
float retval = (float)0.0;
if (speed < MAX_SPEED)
{
current_speed = speed;
retval = this.current_speed;
}
else
{
/* EXCEPTION: */
throw new robot.TooFast();
/* not reached... */
}
return retval;
}