zoukankan      html  css  js  c++  java
  • (转)OpenFire源码学习之七:组(用户群)与花名册(用户好友)

    转:http://blog.csdn.net/huwenfeng_2011/article/details/43413651

    Group

    在openfire中的gorop——组,也可以理解为共享组。什么叫共享组呢。当有一个组名字为“学习组”,当其他用户加入这个组的时候,那么他们会自动成为相互的好友。实际上

    在openfire内,用户的好友不仅仅只是花名册,还包括共同在一个组的成员。当然这个组有很多好处。比如,那我们公司做的一个项目为例。我们做学校老师与家里沟通的的APP,需要预先将老师和家长做成好友,这个就不要重新让用户手动去添加了,可以直接生成放在用一个组内。当然,还有很多其他的用户。大家随意发挥吧,呵呵。。。

    Group通讯

    这里所讲的group通讯主要是将客户端与服务端之间基于group之上的操作通讯。

    比如服务端的CRUD操作,如何知会给客户端。目前据本人了解,openfire提供的客户端版本中都没让用户自己操作gruop的功能,我想在客户端也并不需要这些功能。下面几个小节就主要讲讲服务端的操作。

    终端查询

    客户端发送查询的命令如下:

    [html] view plain copy
     
    1. <iq id="9Fzzk-5" type="get">  
    2.       <sharedgroup xmlns="http://www.jivesoftware.org/protocol/sharedgroup">  
    3.       </sharedgroup>  
    4. </iq>  

    服务端怎么处理呢?

    IQSharedGroupHandler,就是在针对客户端的查询命令处理。该类位于org.jivesoftware.openfire.handler下。

    源码如下:

    [java] view plain copy
     
    1.  @Override  
    2.     public IQ handleIQ(IQ packet) throws UnauthorizedException {  
    3.         IQ result = IQ.createResultIQ(packet);  
    4.         String username = packet.getFrom().getNode();  
    5. <span style="white-space:pre">    </span>//以下是一些校验。。。 此处省略....  
    6. <span style="white-space:pre">    </span>//这里才开始处理。  
    7.         Collection<Group> groups = rosterManager.getSharedGroups(username);  
    8.         Element sharedGroups = result.setChildElement("sharedgroup",  
    9.                 "http://www.jivesoftware.org/protocol/sharedgroup");  
    10.         for (Group sharedGroup : groups) {  
    11.             String displayName = sharedGroup.getProperties().get("sharedRoster.displayName");  
    12.             if (displayName != null) {  
    13.                 sharedGroups.addElement("group").setText(displayName);  
    14.             }  
    15.         }  
    16.         return result;  
    17.     }  

    从源码中,可以看书,groups集合从用户的花名册中得到。RosterManager。

    那么就一起看看源码吧

    [java] view plain copy
     
    1. public Collection<Group> getSharedGroups(String username) {  
    2.        Collection<Group> answer = new HashSet<Group>();  
    3.        Collection<Group> groups = GroupManager.getInstance().getSharedGroups(username);  
    4.        for (Group group : groups) {  
    5.            String showInRoster = group.getProperties().get("sharedRoster.showInRoster");  
    6.            if ("onlyGroup".equals(showInRoster)) {  
    7.                if (group.isUser(username)) {  
    8.                    // The user belongs to the group so add the group to the answer  
    9.                    answer.add(group);  
    10.                }  
    11.                else {  
    12.                    // Check if the user belongs to a group that may see this group  
    13.                    Collection<Group> groupList = parseGroups(group.getProperties().get("sharedRoster.groupList"));  
    14.                    for (Group groupInList : groupList) {  
    15.                        if (groupInList.isUser(username)) {  
    16.                            answer.add(group);  
    17.                        }  
    18.                    }  
    19.                }  
    20.            }  
    21.            else if ("everybody".equals(showInRoster)) {  
    22.                // Anyone can see this group so add the group to the answer  
    23.                answer.add(group);  
    24.            }  
    25.        }  
    26.        return answer;  
    27.    }  

    那么这里比较重要的方法:

     Collection<Group> groups =

    GroupManager.getInstance().getSharedGroups(username);

    这里调用了DAO,首先会从缓存列表中根据用户名获取所拥有的组。如果缓存中不存在则,查询数据库

    缓存Cache<String, Object> groupMetaCache;

    那么group设计到了那些表呢。主要有3张表:

    ofGroup、ofGroupProp、ofGroupUser

    ofGroup该表就是grouo的信息内容:

    ofGroupProp是group的权值属性表:

    Name是权值名称,propValue是值,在上面源码中看到的onlyGroup、everybody就是值了。比如onlyGroup就是该组只对该组成员有效,everybody则是针对所有成员,所有人都能加入这个组当中去。

    ofGroupUser这个是用户与组关系表。里面有三个值

    组名+用户+用户所在该组的权限。

    关于组的信息就说到这,解下继续源码for里面很简单了,就是封装组。

    然后服务端返回客户端组消息,内容如下:

    [html] view plain copy
     
    1. <iq type="result" id="9Fzzk-5" to="zhangf@8ntmorv1ep4wgcy/Spark 2.6.3#android">  
    2.      <sharedgroup xmlns="http://www.jivesoftware.org/protocol/sharedgroup">  
    3.          <group>testg </group>  
    4.      </sharedgroup>  
    5. </iq>  

    从这段消息中可以知道,服务返回是以人(用户)为基础单位,告诉客户端,这个用户(也就是你的好友)所跟您在一起的组。本人认为这样并不是很好。个人认为服务端的返回应该是这样:

    [html] view plain copy
     
    1. <group name=’testgroup’>  
    2. <username>u1</username>  
    3. <username>u2</username>  
    4. ......  
    5. </group>  

    当然openfire并没有这么做,至少在3.8.1的版本没能这么做。这也为了迎合用户的花名册了。

    Ok,查询就都这里。

    控制台上的操作

    当管理将一个用户添加到group中时:

    1、向客户端发送新的iq,告诉它你有新的好友了,你和这个组了的一个人的好友关系是

      both(互为好友为什么互为好友呢,之前说过了,凡事群组的成员都是互为好友的,两个用户都加入对方是both,那么可以自动获取到对方的状态,相当于加了监听)。当然

       这个组内有多少个成员,便会发送多少条消息。内容如下:

    [html] view plain copy
     
    1. <iq type="sgo" id="784-19" to="huwf@hytest240/Spark 2.6.3#10000141" from="hytest240">  
    2.   <query xmlns="jabber:iq:roster">  
    3.     <item jid="10530@hytest240" name="好友名称" subscription="both">  
    4.       <group>groupname#groupdesc</group>  
    5.     </item>  
    6.   </query>  
    7. </iq>  

      注意<group>groupname#groupdesc</group>这里面有个“#”这个是本人自己加的。因为我们项目中把groupname作为了id,desc则为组的名称。实际上我们没有用到描述这个字段。

    2、当管理台删除一个用户的时候,步骤个上面一样。发送的消息内容如下:

    [html] view plain copy
     
    1. <iq type="sgo" id="812-26" to="huwf@hytest240/Spark 2.6.3#10000141" from="hytest240">  
    2.   <query xmlns="jabber:iq:roster">  
    3.     <item jid="10015@hytest240" subscription="remove"/>  
    4.   </query>  
    5. </iq>  

    它只是告诉你,你没这个好友了。当然这个消息是删除正在在线状态的用户。删除其他用户的消息,这里就不在啰嗦了。

    Group事件

    在控制台操作的group出发的事件由GroupManager控制。在GroupManager的构造函数中添加了监听事件。有7个监听事件。

    1、groupCreated。创建group

    1)添加gourp权值属性

    2)加入group缓存

    3)删除元缓存

    2、groupDeleting 删除group

    1)发送iq消息给组内成员“jabber:iq:group:delete”

    2)从缓存中移除

    3)从db中移除

    ......

    花名册

    处理流程

    终端获取流程:

    1、终端发送

    [html] view plain copy
     
    1. <iq id="Ho4CO-2" type="get">  
    2. <query xmlns="jabber:iq:roster"></query>  
    3. </iq>  

    2、系统返回

    [html] view plain copy
     
    1.  <iq type="result" id="Ho4CO-2" to="zhangf@8ntmorv1ep4wgcy/Spark 2.6.3#android">  
    2. <query xmlns="jabber:iq:roster">  
    3.     <item jid="guany@8ntmorv1ep4wgcy" name="关羽" subscription="both">  
    4.          <group>testg </group>  
    5.     </item>  
    6. <item jid="liub@8ntmorv1ep4wgcy" name="liub" subscription="both">  
    7.     <group>我的兄弟</group>  
    8.     <group>testg </group>  
    9. </item>  
    10. <item jid="zhugl@8ntmorv1ep4wgcy" name="zhugl" subscription="from">  
    11.       <group>军机处</group>  
    12. </item>  
    13.    </query>  
    14. </iq>  

    走进源码看IQRosterHandler的处理。IQRosterHandler是服务端对用户花名册的处理。

    IQRosterHandler位于org.jivesoftware.openfire.handler。

    IQRosterHandler中的handleIQ方法,根据客户端的IQ请求中的to属性判别用户是查询还是删除。

    查询:

    [cpp] view plain copy
     
    1. if (recipientJID == null || recipientJID.getNode() == null ||  
    2.                     !UserManager.getInstance().isRegisteredUser(recipientJID.getNode())) {  
    3.                 returnPacket = manageRoster(roster);  
    4.             }  

    manageRoster方法,有两个判断

    1、if (IQ.Type.get == type) 这里从缓存中查找用户好友,并封装消息

    2、else if (IQ.Type.set == type)由分为两种

    1)removeItem移除列表

    2)createRosterItem创建列表

    removeRosterItem:删除用户列表。并广播整个列表好友删除消息。

    组与花名册就先到这,以后还补充。这块还是比较简单。主要看handle这个包下的类。

  • 相关阅读:
    ERP类系统设计学习
    人工智能关键词
    系统性能
    连接不同服务器不同数据库
    socket一个例子
    SQLite
    asp.net 页面缓存、数据缓存
    原生js
    Android 网络调试 adb tcpip 开启方法
    C语言中string char int类型转换
  • 原文地址:https://www.cnblogs.com/wangle1001986/p/7168931.html
Copyright © 2011-2022 走看看