天天看點

OpenDDS Java開發(二):根據IDL進行代碼生成1.編寫IDL檔案2 将IDL編譯為C++代碼3 将已生成代碼編譯為Java代碼4 使用UserManager替換Messenger

目錄

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}