pRTI中的chat例子的Java版分析
来源:互联网 发布:汽车维修管理系统源码 编辑:程序博客网 时间:2024/04/30 18:48
//总体来看,这个例子相当简单。每个联邦成员都订阅一个交互communication,订阅一个Participant对象类的属性name。并且,同时都发布一个交互communication,发布一个Participant对象类的属性name。
//因此,当一个新的联邦成员产生时,他会通过得到别的联邦发布的name属性感知别的联邦的存在。
//
package se.pitch.chat1516;
import hla.rti1516.*;
import se.pitch.prti1516.Encoder;
import se.pitch.prti1516.FederateAmbassadorImpl;
import se.pitch.prti1516.RTI;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
//此前无话,都是对类库的 import
class Chat extends FederateAmbassadorImpl {
private RTIambassador _rtiAmbassador;
private final String[] _args;
private InteractionClassHandle _messageId;
private ParameterHandle _parameterIdText;
private ParameterHandle _parameterIdSender;
private ObjectClassHandle _participantId;
private ObjectInstanceHandle _userId;
private AttributeHandle _attributeIdName;
private String _username;
private volatile boolean _reservationComplete;
private volatile boolean _reservationSucceeded;
private final Object _reservationSemaphore = new Object();
private static final int CRC_PORT = 8989;
private static final String FEDERATION_NAME = "ChatRoom";
//以上为变量定义
private static class Participant {
private String _name;
Participant(String name) { _name = name; }
public String toString() { return _name; }
}
private final Map _knownObjects = new HashMap();
//以下为主程序
public static void main(String[] args)
{
new Chat(args).run();
}
private Chat(String[] args) { _args = args; } //这个是chat类的构造函数
private void run()
{
try
{
//以下程序接收命令行参数或者直接由用户输入CRC host的IP地址
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String rtiHost = "";
if (_args.length > 0) { rtiHost = _args[0]; }
else
{
System.out.print("Enter the IP address of the CRC host [localhost]: ");
rtiHost = in.readLine();
if (rtiHost.length() == 0) { rtiHost = "localhost";}
}
//以下为RTI初始化
try
{
_rtiAmbassador = RTI.getRTIambassador(rtiHost, CRC_PORT);
}
catch (Exception e) {
System.out.println("Unable to connect to CRC on " + rtiHost + ":" + CRC_PORT);
return; }
//以下为destroy联邦
try
{
_rtiAmbassador.destroyFederationExecution(FEDERATION_NAME);
}
catch (FederatesCurrentlyJoined ignored) { }
catch (FederationExecutionDoesNotExist ignored) { }
try
{
File fddFile = new File("Chat.xml");
_rtiAmbassador.createFederationExecution(FEDERATION_NAME, fddFile.toURL());
//上面一句是核心,产生联邦执行,注意,初始化时要读取chat.xml文件
} catch (FederationExecutionAlreadyExists ignored) { }
_rtiAmbassador.joinFederationExecution("Chat", FEDERATION_NAME, this, null);
//上面一句是加入联邦
// Subscribe and publish interactions
//下面是得到交互和参数句柄,分别是交互Communication,参数Message和Sender
_messageId = _rtiAmbassador.getInteractionClassHandle("Communication");
_parameterIdText = _rtiAmbassador.getParameterHandle(_messageId, "Message");
_parameterIdSender = _rtiAmbassador.getParameterHandle(_messageId, "Sender");
//下面是订阅交互Communication和发布交互Communication
_rtiAmbassador.subscribeInteractionClass(_messageId);_rtiAmbassador.publishInteractionClass(_messageId);
// Subscribe and publish objects
//下面是得到对象类句柄
_participantId = _rtiAmbassador.getObjectClassHandle("Participant");
//得到对象类中Name属性句柄,并将该属性加入一个attributeSet集合
_attributeIdName = _rtiAmbassador.getAttributeHandle(_participantId, "Name");
AttributeHandleSet attributeSet = _rtiAmbassador.getAttributeHandleSetFactory().create();attributeSet.add(_attributeIdName);
//订阅属性集和发布属性集,其实这时属性集中只有一个属性,即name属性
_rtiAmbassador.subscribeObjectClassAttributes(_participantId, attributeSet);_rtiAmbassador.publishObjectClassAttributes(_participantId, attributeSet);
// Reserve object instance name and register object instance
//这个do--while循环的功能不麻烦,就是保证注册对象的名字的唯一性。但是实现机制不简单。联邦需要和RTI实施两次
//交互,一次是联邦调用reserveObjectInstanceName函数通知RTI需要预订某名字;一次是RTI通过后面的
//objectInstanceNameReservationSucceeded函数和objectInstanceNameReservationFailed函数两个回调
//通知联邦,名字预订的结果是成功还是失败。
//这里复杂性还体现在几个变量的同步机制上,尤其是在多线程环境下
do
{
System.out.print("Enter your name: ");
_username = in.readLine();
try
{
_reservationComplete = false;
//此函数属于标准RTI函数,功能是注册一个对象之前必须先预订其名字,RTI将保证其唯一性
_rtiAmbassador.reserveObjectInstanceName(_username);
synchronized (_reservationSemaphore)
{
// Wait for response from RTI
while (!_reservationComplete)
{
try { _reservationSemaphore.wait(); }//wait阻塞,等待notify唤醒
catch (InterruptedException ignored) { }
}
}
if (!_reservationSucceeded)
{
System.out.println("Name already taken, try again.");
}
} catch (IllegalName e) { System.out.println("Illegal name. Try again."); }
catch (RTIexception e)
{
System.out.println("RTI exception when reserving name: " + e.getMessage());
return;
}
}while (!_reservationSucceeded);
//联邦注册对象实例,参数分别是对象类句柄和用户输入的名字name
_userId = _rtiAmbassador.registerObjectInstance(_participantId, _username);
//注意到,通常registerObjectInstance函数调用是和discoverObjectInstance回调一并使用的。但是本例中并不是这样
//联邦中并没有实现discoverObjectInstance接口。则联邦对别的联邦注册对象的感知,是通过名字属性
//(updateAttributeValue和reflectAttributeValue函数对)的传递来实现的。
System.out.println("Type messages you want to send. To exit, type . ");
while (true)
{
System.out.print("> ");
String message = in.readLine();
if (message.equals(".")) { break; }
ParameterHandleValueMap parameters=_rtiAmbassador.getParameterHandleValueMapFactory().create(1);
parameters.put(_parameterIdText, Encoder.makeHLAunicodeString(message));parameters.put(_parameterIdSender, Encoder.makeHLAunicodeString(_username));
//发送交互
_rtiAmbassador.sendInteraction(_messageId, parameters, null);
}
//上面程序中,用户敲击.符号,发出退出命令之前,系统一直在此循环,接收用户输入的消息并发送交互
//下面程序功能:当用户敲击.符号时,联邦结束
_rtiAmbassador.resignFederationExecution(ResignAction.DELETE_OBJECTS_THEN_DIVEST);
try
{
_rtiAmbassador.destroyFederationExecution(FEDERATION_NAME);
}
catch (FederatesCurrentlyJoined ignored) { }
_rtiAmbassador = null; }
catch (Exception e) { e.printStackTrace();
}
}
public final void receiveInteraction(InteractionClassHandle interactionClass, ParameterHandleValueMap theParameters, byte[] userSuppliedTag, OrderType sentOrdering, TransportationType theTransport)
{
//这个是回调函数,当联邦成员接收到交互时被RTI调用
if (interactionClass.equals(_messageId))
{
if (!theParameters.containsKey(_parameterIdText))
{
System.out.println("Bad message received: No text.");
return;
}
if (!theParameters.containsKey(_parameterIdSender))
{
System.out.println("Bad message received: No sender.");
return;
}
//上面是检查消息中是否包含必要的信息
String message = Encoder.stringFromHLAunicodeString((byte[]) theParameters.get(_parameterIdText));String sender = Encoder.stringFromHLAunicodeString((byte[]) theParameters.get(_parameterIdSender));System.out.println(sender + ": " + message); System.out.print("> ");
}
}
public final void objectInstanceNameReservationSucceeded(String objectName)
{
synchronized (_reservationSemaphore)
{
_reservationComplete = true;
_reservationSucceeded = true;
_reservationSemaphore.notify();
}
}
public final void objectInstanceNameReservationFailed(String objectName)
{
synchronized (_reservationSemaphore)
{
_reservationComplete = true;
_reservationSucceeded = false;
_reservationSemaphore.notify();
}
}
//这个也是回调函数。当责任联邦成员删除其管辖的对象时(通常是调用RTI接口函数deleteObjectInstance),订阅了这个对象类所有或者部分属性的联邦成员将收到由RTI为每一个删除实例而调用的服务 removeObjectInstance
//此例中并不是专业。现猜测是前面的
//resignFederationExecution(ResignAction.DELETE_OBJECTS_THEN_DIVEST)掉用间接调用了deleteObjectInstance函数
public void removeObjectInstance(ObjectInstanceHandle theObject, byte[] userSuppliedTag, OrderType sentOrdering) {
Participant member = (Participant) _knownObjects.remove(theObject);
if (member != null)
{
System.out.println("[" + member + " has left]");
}
}
//回调函数。当责任联邦成员修改了管辖对象的属性时,订阅了该属性的联邦成员将被RTI调用这个回调函数
//与updateAttributeValues配对使用,即当联邦调用updateAttributeValues函数时,会触发RTI调用这个回调函数
//此例中也不典型。 因为本联邦中其实并没有任何地方显式调用updateAttributeValues。而是在provideAttributeValueUpdate回调
//中间接调用updateAttributeValues
//而接下来的问题是:provideAttributeValueUpdate回调函数是和requestAttributeValueUpdate函数配对使用的。本联邦中也没有
//对requestAttributevalueUpdate函数的显式调用
//现在猜测(也经过调试证明):假设A联邦先启动,B后启动。则当B调用subscribeObjectClassAttributes函数后并且交出CPU控制权
//时(比如调用in.readline时),RTI就会调用reflectAttributeValues函数使B感知A联邦所维护的对象及其属性name。
//因此,猜测是B调用subscribeObjectClassAttributes函数时,调用了requestAttributevalueUpdate函数
public final void reflectAttributeValues(ObjectInstanceHandle theObject, AttributeHandleValueMap theAttributes, byte[] userSuppliedTag, OrderType sentOrdering, TransportationType theTransport)
{
if (!_knownObjects.containsKey(theObject))
{
if (theAttributes.containsKey(_attributeIdName))
{
String memberName = Encoder.stringFromHLAunicodeString((byte[]) theAttributes.get(_attributeIdName));
Participant member = new Participant(memberName);
System.out.println("[" + member + " has 。joined]");
System.out.print("> "); _knownObjects.put(theObject, member);
}
}
}
//这个函数是回调函数。当其他联邦成员调用requestAttributeValueUpdate请求时,RTI将回调这个函数。而在这个函数内部,将再次调用联邦代理的函数updateAttributeValues显示地再次更新属性
public final void provideAttributeValueUpdate(ObjectInstanceHandle theObject, AttributeHandleSet theAttributes, byte[] userSuppliedTag)
{
if (theObject.equals(_userId) && theAttributes.contains(_attributeIdName))
{
new Thread()
{
public void run()
{
updateMyName();
}
}.start();
}
}
//由上面方法provideAttributeValueUpdate调用
private void updateMyName()
{
try
{
AttributeHandleValueMap attributeValues = _rtiAmbassador.getAttributeHandleValueMapFactory().create(1);
attributeValues.put(_attributeIdName, Encoder.makeHLAunicodeString(_username));_rtiAmbassador.updateAttributeValues(_userId, attributeValues, null);
} catch (RTIexception ignored) { }
}
} //类Chat定义结束
- pRTI中的chat例子的Java版分析
- pRTI中的testfederate例子分析
- pomelo广播的实现(chat例子分析)
- Line Chat 例子
- 解决pomelo官方的chat例子不好用的问题
- Java初始化的例子分析
- muduo库chat server的shared_ptr和TLS实现分析
- java分析html文档的例子
- JAVA CHAT SCALE
- JAVA CHAT SCALE2
- JAVA CHAT SCALE3
- Java之Chat历程
- java中的线程死锁的一个例子
- Java中的事件、监听器的简单例子
- java中的单例模式的例子
- Java Socket编程实现在终端上的双工Chat
- java 多线程 例子分析
- ICE Chat Demo 实例分析
- VB:绘图示例—屏保软件设计1
- ASP.NET4.0中客户端ID的生成
- 将一个字符串中的各个位按递增排序的最大整数打印出来
- 设计模式 Design Parttern ——外观模式Facade
- Linux常用命令和工具摘要 (持续更新中)
- pRTI中的chat例子的Java版分析
- 难道说这个就是生活吗?
- 关于高端ARM处理器选型的一些个人看法(作者:gooogleman)
- LINUX command not found
- C++编程规范整理(一)
- 解决svn服务端与apache整合安装不正确的问题
- JSTL的小型悲剧事件 感觉自己玩了一次走进科学
- javascript修改struts form的action属性
- [ADO.NET]怎样用DataSet更新数据库