OpenDDS Java开发(二):根据IDL进行代码生成

目录

1.编写IDL文件

2 将IDL编译为C++代码

3 将已生成代码编译为Java代码

4 使用UserManager替换Messenger


1.编写IDL文件

IDL是Interface description language的缩写,指接口描述语言,是CORBA规范的一部分,是跨平台开发的基础。

关于IDL的介绍可参见:https://blog.csdn.net/wyc12306/article/details/79577389

这里以Messenger示例中的Messenger.idl为例说明:

module Messenger {

#pragma DCPS_DATA_TYPE "Messenger::Message"
#pragma DCPS_DATA_KEY "Messenger::Message subject_id"

  struct Message {
    string from;
    string subject;
    long subject_id;
    string text;
    long   count;
  };
};

它由三部分组成:

  • module:最外层,可以理解为待生成的工程名字
  • pragma指令:指定了OpenDDS项目中传输的数据类型和键,每个数据类型可以有零到多个键,键的作用是标识不同的实例
  • struct:pragma指令指定的数据类型

在本例的Message结构体中,有5个成员,为字符串或数字类型,在IDL中,主要有如下类型:

基本类型:

1)整数类型:short(2字节)、long(4字节)、long long(8字节),及它们的无符号类型

2)浮点型:float(4字节)、double(8字节)、long double(16字节)

3)字符型:char、wchar、string、wstring

4)布尔型:boolean

5)八进制型:octet

结构类型有struct、interface、union等。

一般常用的就是string、double、long、boolean这几个。

在同一个module下,可以编写很多个struct,并且可以为每一个struct都添加#pragma指令,为了简化,还是只以一个为例,现在创建一个名为UserManager的module,其中包含User结构体,每个User都包含姓名(string)、性别(以boolean表示,true代表男,false代表女,反过来也一样)、年龄(long)、身高(double)和一个唯一ID(long):

module UserManager {

#pragma DCPS_DATA_TYPE "UserManager::User"
#pragma DCPS_DATA_KEY "UserManager::User id"

  struct User {
    long id;
    string name;
    boolean sexual;
    long age;
    double height;
  };
};

2 将IDL编译为C++代码

官方文档第10章描述是通过编写mpc文件生成sln工程,直接将C++和Java代码都生成出来,我实际测试是不行的。必须先按照第2章的步骤生成C++代码之后,才能再按照第10章的步骤生成Java代码。

编译时需要利用C++编译器,如果是Windows环境,可以在Visual Studio的开发人员命令行下运行。首先使用tao_idl.exe编译刚刚编写的idl文件:

E:\OpenDDS-3.13>tao_idl UserManager.idl
tao-idli_2AUI68.cpp
processing UserManager.idl

此时会生成:UserManagerC.cpp、UserManagerC.h、UserManagerC.inl、UserManagerS.cpp、UserManagerS.h五个文件

然后使用opendds_idl进行编译:

E:\OpenDDS-3.13>opendds_idl UserManager.idl
tao-idli_VTx7fz.cpp
processing UserManager.idl

此时生成了:UserManagerTypeSupport.idl、UserManagerTypeSupportImpl.cpp、UserManagerTypeSupportImpl.h三个文件

对新生成的UserManagerTypeSupport.idl同样使用tao_idl进行编译

3 将已生成代码编译为Java代码

首先按第10章步骤,生成UserManager_Export.h(这个名字可以随便起,只要下面的mpc文件和这里保持一致即可):

E:\OpenDDS-3.13>generate_export_file.pl UserManager>UserManager_Export.h

然后编写mpc文件以生成工程,可以把%OPENDDS_HOME%\java\tests\messenger\messenger_idl目录下的messenger_idl_test.mpc拷出来改一下:

project: dcps_test_java {

  idlflags     += -Wb,stub_export_include=UserManager_Export.h \
                  -Wb,stub_export_macro=UserManager_Export
  dcps_ts_flags+= -Wb,export_macro=UserManager_Export
  idl2jniflags += -Wb,stub_export_include=UserManager_Export.h \
                  -Wb,stub_export_macro=UserManager_Export
  dynamicflags += UserManager_BUILD_DLL

  specific {
    jarname     = UserManager
  }

  TypeSupport_Files {
    UserManager.idl
  }
}

 然后进行编译:

E:\OpenDDS-3.13>mwc.pl -type vs2017 UserManager.mpc

此时应该可以生成sln文件,如果出现下面的异常,可考虑使用mpc.pl进行编译,它会产生vcxproj文件:

Using .../OpenDDS-3.13/ACE_wrappers/bin/MakeProjectCreator/config/MPC.cfg
CIAO_ROOT was used in the configuration file, but was not defined.
DANCE_ROOT was used in the configuration file, but was not defined.
Generating 'vs2017' output using UserManager.mpc
UserManager.mpc: line 1:
ERROR: No workspace was defined
ERROR: Unable to process: UserManager.mpc

注意,上面的-type选项的值需要根据实际情况确定,我使用的VS 2019经测试可以打开和编译VS 2017工程。

接下来,打开工程,会提示设置Windows SDK,直接确认即可,如果电脑是64为系统,需要将上方“Debug”旁边的x86换成x64,接着,执行“生成”-“生成解决方案”即可。

在生成过程中,可能会提示缺少 jni_md.h,该文件位于 %JAVA_HOME%\include\win32 目录下,复制到 %OPENDDS_HOME%\java\idl2jni\runtime 目录下即可。

此时,按照我们刚刚编写的mpc文件,就可以得到UserManager.jar 和 UserManagerd.dll(因为是Debug模式下生成,如果是Release模式则不会有d),剩下的文件都可以删除了。

4 使用UserManager替换Messenger

我们打开 OpenDDS Java开发(一):理解Messenger示例 中创建的工程,稍作修改。

首先是移除对messenger_idl_test.jar的依赖,并添加UserManager.jar。此时三个java文件肯定都会报错标红,把这些地方都改掉就好。

对TestPublisher进行修改:

第1处:
MessageTypeSupportImpl servant = new MessageTypeSupportImpl();

-> 修改为:

UserTypeSupportImpl servant=new UserTypeSupportImpl();

第2处:
MessageDataWriter mdw = MessageDataWriterHelper.narrow(dw);
Message msg = new Message();
msg.subject_id = 99;
int handle = mdw.register_instance(msg);
msg.from = "OpenDDS-Java";
msg.subject = "Review";
msg.text = "Worst. Movie. Ever.";
msg.count = 0;
int ret = RETCODE_TIMEOUT.value;
for (; msg.count < N_MSGS; ++msg.count) {
    while ((ret = mdw.write(msg, handle)) == RETCODE_TIMEOUT.value) {
    }
    if (ret != RETCODE_OK.value) {
        System.err.println("ERROR " + msg.count +
            " write() returned " + ret);
    }
    try {
        Thread.sleep(100);
    } catch(InterruptedException ie) {
    }
}

-> 修改为:

UserDataWriter writer=UserDataWriterHelper.narrow(dw);
User user=new User();
int handle=writer.register_instance(user);
user.name="zhangsan";
user.age=20;
user.sexual=true;
user.height=1.75;
user.id=1;
writer.write(user,handle);

对TestSubscriber进行修改:

MessageTypeSupportImpl servant = new MessageTypeSupportImpl();

-> 修改为:

UserTypeSupportImpl servant=new UserTypeSupportImpl();

对DataReaderListenerImpl进行修改,先把Message全替换成User:

if (mh.value.count < 0 || mh.value.count >= counts.size()) {
    invalid_count = true;
}
else {
    if (counts.get(mh.value.count) == false){
        counts.set(mh.value.count, true);
    }
    else {
        prefix = "ERROR: Repeat ";
    }
}
System.out.println(prefix + "Messenger.User: subject    = " + mh.value.subject);
System.out.println("         subject_id = "
   + mh.value.subject_id);
System.out.println("         from       = " + mh.value.from);
System.out.println("         count      = " + mh.value.count);
System.out.println("         text       = " + mh.value.text);
System.out.println("SampleInfo.sample_rank = "
   + sih.value.sample_rank);

-> 修改为:

System.out.println("User "+mh.value.id+":{name:"+mh.value.name+",age:"+mh.value.age+",sexual:"+(mh.value.sexual?"male":"female")+",height:"+mh.value.height+"}");

然后把VM option中的 -Djava.library.path 修改为:

-Djava.library.path=<UserManager.jar所在路径>;E:\OpenDDS-3.13\lib

因为-DCPSConfigFile选项没改,所以还是在messenger示例目录下运行DCPSInfoRepo,分别运行TestPublisher和TestSubscriber后,在订阅者一端打印了如下消息,说明替换成功:

User 1:{name:zhangsan,age:20,sexual:male,height:1.75}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章