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}

 

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