Jade Dungeon

消息的发送与接收

消息类的抽象

一个XMPP的基本Message消息形式如下:

<message from='aa@gmail.com/handpay-pc1ECC80A8' 
	to='bb@jabber.org' type='chat' id='purpled65d5457'>
	<body>hello</body>
</message>

从上面的例子中可以看到message报文的主要成员有from属性、to属性、 type属性、id属性和子元素body。对于这些特征可以抽象出Message类:

消息类

在完成了对Message类的定义以后,就可以着手实现接收与发送消息的逻辑。

发送消息

发送消息的实现逻辑非常简单,XMPPConnectionwrite()方法可以直接把文本写入 输入流:

发送消息的流程

abstract class XMPPConnection(override val serviceName: String, 
	override val port: Int, override val proxyInfo: ProxyInfo) 
	extends Connection(serviceName: String, port: Int, proxyInfo: ProxyInfo) 
	with MessageProcesser with AuthInfo with Logging
{
	/* ... */

	def write(str: String) {
		if (null != str) ioStream.packetWriter ! str
	}
	
	/* ... */

用户在使用本工具库发送消息时,可以通过直接调用Message实例的toXML方法生成要 发出的报文:

	val elem = new Message("jadexmppIBIDM-0", "aa@gmail.com", 
		"bb@gmail.com", "hello")
	conn.write(elem.toXML.toString)

消息类的需要属性id表示唯一的标识,type标识消息是普通消息还是群聊:

override def addAttributeToXML(node: Elem): Elem = { 
	super.addAttributeToXML(node) % 
	Attribute(None, "id", newTextAttr(id), 
		Attribute(None, "type", newTextAttr("chat"), Null))
}

<message>标签的内部就是消息子元素:

def nodeXML(childElementXML: NodeBuffer): Elem = <message>{
	childElementXML
}</message>

而消息子元素为<active>标签加上<body>标签,消息的内容就在<body>标签内:

override def childElementXML: NodeBuffer = {
	val nb = super.childElementXML
	nb += <active xmlns="http://jabber.org/protocol/chatstates"/>
	nb += <body>{msgStr}</body>
	nb
}

接收消息

为了处理收到的消息,需要定制专门的处理器,在这里定义了MessageHandler类。 由于本项目是作为一个工具库交给用户使用的,所以不可能事先知道用户在他们的项目 中是如何使用收到的XMPP消息的(是作为聊天工具显示在屏幕上还是合为远程控制执行 命令)。

为了方便地在MessangeHandler中调用最终用户定义的逻辑,可以声明一个名为 MsgRecvHandler的接口,它包含一个公有的方法onMessageReceive(msg)。用户可以 通过实现这个方法来写入自己的业务逻辑。MessageHandler内部有有一个 MsgRecvHandler类型的列表,如图\ref{fig:ch08.MsgRecvHandler.png}。

消息处理类

MessageHandler类的process()方法会从收到的XML文档中提取出fromtoidbody等信息,构建出Message实例作为参数。然后逐一调用每个MsgRecevhandler 成员的onMessageReceive()方法,触发所有用户的业务逻辑。处理过程如图 \ref{fig:ch08.msghdl.png}。

接收消息