pRTI中的testfederate例子分析

来源:互联网 发布:mac pro 2016 发布时间 编辑:程序博客网 时间:2024/05/18 03:56

从pitch公司下载的testfederate例子代码不全,很多菜单响应函数都被注释掉了,直接去掉注释会出现很多编译错误。因此,不建议使用那个例子。 

 

本文中例子是从http://www.mitre.org/tech/hla_book/ 下载的最新的testfederate例子,此代码齐全,可以编译运行。

 

编译运行此例子的步骤如下:

 

1 在path环境变量下加入jdk的bin目录,同时在classpath环境变量下加入lib/prti.jar;

2 运行C:/Program Files/prti1516/samples/book/src>javac org/mitre/hla/book/test_federate/*.java命令编译程序,注意此命令是在src作为当前目录的情况下执行的。

3 直接在C:/Program Files/prti1516/samples/book目录下运行rti.bat和testfed.bat两个批处理文件,注意修改批处理文件,把jre程序换成java程序。

 

--------------------------------------------------------------------------------------------------------------

此例子加入GUI,用户可以通过菜单执行方式测试。基本的结构跟Chat例子很相似:所有federate都使用同样的一个程序,通过不同的joinFederateExecution来产生不同的联邦。

 

FED文件不是xml格式的,而是书上提到的那种格式。

 

源代码中对不同的菜单项进行了编号,因此很容易找到其对象的处理逻辑。基本上所有的菜单响应都分成三部分:

 

第一部分,在TestFederateFrame.java中通过addActionListener函数加入对菜单项的处理函数,比如

 

 

    createFedExMenuItem.addActionListener(new java.awt.event.ActionListener() {

      public void actionPerformed(ActionEvent e) {

        createFedEx_Action(e);

      }

    });

 

 

第二部分,在TestFederateFrame.java中的消息响应函数,比如createFedEx_Action:

 

 

void createFedEx_Action(ActionEvent event)

{

StringsDialogProxy proxy = new StringsDialogProxy();

String[] labels = {

 "Federation execution name:",

 "FED:"

};

String[] defaults = {

      "restaurant_1",

      ""};

    //file:/c://mydocu~1//hla//book//code//config//fed_example.fed

BrowserFactory[] browsers = {null, _fileBrowser};

int result = proxy.queryUser(

 this,

 "Create Federation Execution",

 labels,

 defaults,

 browsers);

if (result == StringsDialog.CANCEL) return;

else if (result == StringsDialog.OK) {

 String[] stuff = proxy.results();

  _impl.createFederationExecution(stuff);

  }

  else {

    post("StringsDialog returned " + result);

  }

  }

第三部分,在上述函数中调用TestFederate.java中的函数,比如_impl.createFederationExecution
第四部分,在TestFederate.java中的createFederationExecution函数中,调用RTI的API,比如_rti.createFederationExecution(stuff[0], fedURL);具体该函数示例如下:
void createFederationExecution(String[] stuff) {
    try {
      URL fedURL;
      String urlString;
      if (stuff[1].equals("")) { //we're defaulting it
        urlString =
          (String)_properties.get("CONFIG")
          + _fileSeparator
          + stuff[0]
          + ".fed";
      }
      else urlString = stuff[1];
      fedURL = new URL(urlString);
      _userInterface.post("4.2 Starting to create federation execution with FED "
        + urlString + "...");
      _rti.createFederationExecution(stuff[0], fedURL);
      _userInterface.post("Done.");
    }
    catch (MalformedURLException e) {
      _userInterface.post("EX 4.2 CreateFederationExecution: FED path URL malformed:" + e);
    }
    catch (Exception e) {
      _userInterface.post("EX 4.2 CreateFederationExecution: " + e);
    }
  }
---------------------------------------------------------------------------------------------------------------------
下面,针对不同的功能具体论述一下其实现机制
(1)联邦执行的创建和联邦的创建
此功能比较简单,启动第一个联邦后,可以运行菜单4.2,创建联邦执行,可以命名此联邦执行;然后采用菜单4.4加入联邦执行。此后启动任何一个联邦时,都要使用菜单4.4加入联邦执行。
(2)同步点的实现。
同步点菜单中,主要有三个功能:
    jMenu5.setText("Sync points");
    jMenuItem5.setText("4.6 Register synchronization point...");
    jMenuItem6.setText("4.6 Register for federates...");
    jMenuItem7.setText("4.9 Synchronization point achieved...");
执行此功能时,某联邦先会调用4.6功能,注册一个同步点,注册时需要输入同步点的label和用户tag。注册同步点将触发RTI调用注册同步点的联邦的回调函数synchronizationPointRegistrationSucceeded函数, 同时也将触发RTI调用每个联邦的回调函数announceSynchronizationPoint,通知每个联邦此同步点。
接着,当某一个联邦到达该同步点时,使用菜单4.9,报告RTI其已经到达某同步点。当所有联邦都到达某同步点时,RTI将回调所有联邦的回调函数)federationSynchronized通知所有联邦成员,联邦执行已经同步。

 

 

(3)订阅/发布机制的实现

 

与此有关的菜单项有9个,表示为5.x。需要注意的是,这里的大多数功能都需要预先知道对象属性的handle。因此,需要先调用10.x相关功能获取特定属性的handle。

 

比如,我们可以先通过10.2功能获取某对象类的handle,比如输入ObjectRoot.Restaurant将能得到餐馆对象类的handle。这里注意输入对象类名字时,需要输入全路径。即从根对象类输入直到所要获取handle的对象类。

 

然后,可以通过10.4功能获取某对象类属性的handle,比如输入对象类handle为2,输入属性名字为position,则可以得到position属性的handle为100.

 

此时,我们已经获取到了需要的对象类和属性的handle,就可以进行发布和订阅的配置了。比如,调用5.2功能,输入对象类handle为2,输入属性handle为100,就可以得到发布对象类2的100号属性,即position属性。同理,可以调用5.6功能,订阅对象类2的100号属性。可以看到,RTI将调用发布联邦的回调函数(在FedAmbImpl.java中)startRegistrationForObjectClass,通知该联邦,有别的联邦已经订阅了它方法发布的属性position。

 

(4)属性的更新和反射

 

前面我们已经进行了属性的发布和订阅,接下来就可以进行属性值的更新和反射了。注意, 在属性值更新和反射之前,我们还需要注册对象实例。因为,只有对象实例才有属性值。此时,调用6.2功能注册对象实例,输入对象类句柄为2.则注册成功后,订阅此属性的联邦将被回调discoverObjectInstance函数,得到别的联邦所注册的对象实例句柄,102。

 

然后就可以调用6.4功能进行属性值的更新,输入参数为实例handle为102,属性句柄为100,值为xxxxx,则RTI将调用订阅该属性的联邦的回调函数reflectAttributeValues来通知属性值的更新。

 

 

(5)时间管理

 

这里以时间推进为例。首先在第一个联邦中调用8.2功能,使其变为可以发出TSO事件的联邦(local time为0,lookahead为0.2)。此举将使RTI调用回调函数timeRegulationEnabled进行确认。

 

然后在第二个联邦中调用8.5功能,使其改变为时间受限联邦。此举将使RTI调用回调函数timeConstrainedEnabled进行确认。

 

然后在第一个联邦中调用8.8TAR,请求时间推进到0.2,第二个联邦中调用8.8TAR,请求时间推进到0.5。则第一个联邦中会被RTI调用回调函数time adv grant,确认时间可以推进到0.2.此时第二个联邦时间还是不能推进,因为0.2+0.2=0.4还是小于0.5。若第一个联邦再次调用8.8TAR,请求时间推进到0.4,则第一个联邦将会被RTI调用回调函数time adv grant,确认时间可以推进到0.4,此时第二个联邦也被调用回调)time adv grant,确认时间可以推进到0.5.

 

关于时间管理,请看运行截图