Tigase8.0 源代码分析:二、MUC源码分析
原文链接: https://www.cnblogs.com/eyecool/p/10451981.html
XMPP在其XEP-0045扩展中定义了一个用于多用户文本会议(群聊)的协议,类似于聊天室、QQ群等。由于它作为一个标准协议在定义模型上力求完备,涵盖了现实中的绝大部分IM产品模型,而现实中的IM产品基本都只实现了XMPP定义的模型中的一个子集。
XMPP定义的一些基本概念:
房间:房间的JID标识 <room@service> (例如, <jdev@conference.jabber.org>), 这里 "room" 是房间的名称而 "service" 是多用户聊天服务运行所在的主机名
房客:房客的JID标识<room@service/nick>,nick是房客在房间的昵称
岗位:表达了用户和房间的长期关系。XMPP定义的岗位有:所有者(owner)、管理者(admin)、成员(member)、排斥者(outcast)
角色:表达了用户和房间的临时联系,它只存在与一次访问期间。XMPP定义的角色有:主持人(moderator)、与会者(paticipant)、游客(visitor)
有关岗位、角色及其权限详细描述,参考协议规范描述(角色、岗位和权限)
pom.xml里加入 依赖引用
1 2 3 4 5 | <dependency> <groupId>tigase</groupId> <artifactId>tigase-muc</artifactId> <version> 3.0 . 0 -SNAPSHOT</version> </dependency> |
config.tdsl 配置文件中加入配置:
1 2 3 4 5 6 | muc( class : tigase.muc.MUCComponent) { defaultRoomConfig { 'tigase#presence_delivery_logic' = 'PREFERE_LAST' 'muc#roomconfig_persistentroom' = 'true' } } |
MUC源码首先从 MUCComponent 这个组件开始分析 :
1 2 3 4 5 | @Bean (name = "muc" , parent = Kernel. class , active = true ) @ConfigType (ConfigTypeEnum.DefaultMode) @ClusterModeRequired (active = false ) public class MUCComponent extends AbstractKernelBasedComponent {}在 |
在前一节已说明怎么扫描加载相关的Class,类似这里,加载Kernel.class的时候,会把parent=Kernel.class的Bean全部加载到容器中
MUCComponent 也实现了RegistrarBean,在初始化的时候,会被调用 public void register(Kernel kernel) {} 函数进行注册工作
1 2 3 | public abstract class AbstractKernelBasedComponent extends AbstractMessageReceiver implements XMPPService, DisableDisco, RegistrarBean {} |
由于用户客户端发来的MUC消息协议为:to=<room@service/nick> 例如 llooper@muc.llooper/spark ,目的地上直接表示到muc.组件上,所以MUC模块入口就是在MUCComponent 类processPacket(Packet packet) 方法上
1 2 3 4 | @Override public void processPacket(Packet packet) { stanzaProcessor.processPacket(packet); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | public void processPacket(Packet packet) { if (log.isLoggable(Level.FINER)) { log.finer( "Received: " + packet.getElement()); } //查找是否为Response模式,则由Handler来处理 Runnable responseHandler = responseManager.getResponseHandler(packet); boolean handled; if (responseHandler != null ) { handled = true ; responseHandler.run(); } else { //否则调用处理包的函数 handled = this .process(packet); } if (!handled) { final String t = packet.getElement().getAttributeStaticStr(Packet.TYPE_ATT); final StanzaType type = (t == null ) ? null : StanzaType.valueof(t); if (type != StanzaType.error) { throw new ComponentException(Authorization.FEATURE_NOT_IMPLEMENTED); } else { if (log.isLoggable(Level.FINER)) { log.finer(packet.getElemName() + " stanza with type='error' ignored" ); } } } 。。。。。。 } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | private boolean process( final Packet packet) throws ComponentException, TigaseStringprepException { boolean handled = false ; if (log.isLoggable(Level.FINER)) { log.finest( "Processing packet: " + packet.toString()); } //找到匹配的Module来处理 for (Module module : this .modules) { if (module.canHandle(packet)) { handled = true ; if (log.isLoggable(Level.FINER)) { log.finer( "Handled by module " + module.getClass()); } module.process(packet); if (log.isLoggable(Level.FINEST)) { log.finest( "Finished " + module.getClass()); } } } return handled; } |
例如MUC中实现的Module有如下:
这里的逻辑比较简单,也就是根据包的节类型等信息,来匹配感兴趣的处理Module,来进行处理
再来看下 module.canHandle(packet) 是怎么样找到匹配的Module来处理的:
1 2 3 4 | default boolean canHandle(Packet packet) { Criteria criteria = getModuleCriteria(); return criteria != null && criteria.match(packet.getElement()); } |
private final String[] names; private final String[] xmlns;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <br> @Override public boolean ElemPathCriteria.match(Element element) { //判断<iq> packet的名字如iq是否和本module中定义name一致 boolean match = element.getName().equals(names[ 0 ]); if (match && xmlns[ 0 ] != null ) {<br> //并且判断命名空间是否一致 match &= xmlns[ 0 ].equals(element.getXMLNS()); } Element child = element; int i = 1 ;<br> //例如packet <iq><set>xxx</set></iq> 则name为数组{"iq","set"},前面判断了iq,这里判断set是否一致,如果还存在子节点,则依次比较是否一致 for (; i < names.length; i++) { String n = names[i]; String x = xmlns[i]; // child = child.getChildStaticStr(n, x); match &= child != null ; if (!match) { return match; } } // TODO Auto-generated method stub return match; } |
例如针对出muc的 <presence> 由 PresenceModuleImpl 进行业务逻辑处理
1 2 3 4 5 6 7 8 9 | @Bean (name = PresenceModuleImpl.ID, parent = MUCComponent. class , active = true ) public class PresenceModuleImpl extends AbstractMucModule implements PresenceModule { protected static final Logger log = Logger.getLogger(PresenceModule. class .getName()); private static final Criteria CRIT = ElementCriteria.name( "presence" ); } |
标签: