Openfire 服务器端是支持插件开发的,开发过程可能会涉及到数据库的操作,本篇文章专注于Openfire 插件的部分,对服务器端涉及到数据库的开发只做简单介绍。

Openfire 是一个用Java 实现的XMPP 服务器,客户端可以通过IQ 的方式与其进行通信(其实就是XML),客户端和服务器之间的通信是依靠底层Smack 库提供的各种功能来完成的。其实利用插件方式来扩展Openfire 服务器端主要有两种扩展方式,一种是对服务器控制台页面进行扩展(不是本文的主要内容),其实就是遵循Openfire 页面的布局方式,进行相应的页面扩展和功能扩展;另一种是对通信功能进行扩展。本文主要针对后者进行具体的描述

本篇文章的结构如下:

1、创建plugin.xml(这是整个插件最关键的文档)
2、创建服务器插件实例(实现Plugin 接口的一个类还有一批IQHandler)
3、打包插件(Openfire 插件也有自己的打包方式)和部署插件

好滴,实刀实枪的来动手做吧

1、创建plugin.xml

初次开发Openfire 和Spark 插件的时候,很容易把二者搞混,千万记得,这里是Openfire 的plugin.xml 不是第二篇文章说的那个啦!

<?xml version="1.0" encoding="UTF-8"?>
<plugin>
    <!-- Main plugin class  这里是最重要滴-->
    <class>com.im.server.plugin.GroupTreePlugin</class>

<!-- Plugin meta-data -->
    <name>GroupTreePlugin</name>
    <description>This is the group plugin.</description>
    <author>Phoenix</author>

<version>1.0</version>
    <date>14/03/2008</date>
    <url>http://localhost:9001/openfire/plugins.jsp</url>
    <minServerVersion>3.4.1</minServerVersion>
    <licenseType>gpl</licenseType>

<!-- Admin console entries -->
    <adminconsole>
        <!-- More on this below -->
    </adminconsole>
</plugin>

最重要的那一行我已经标记出来啦,就是你这个插件的初始化和垃圾清理类,例子中是在com.im.server.plugin 包中的GroupTreePlugin 类,下文会对这个类进行详细描述。其余的都是描述信息,只要你提供了正确的描述信息,一般都不会出错。建议初次开发者,在写完plugin.xml 文件后,写一个简单的Plugin 实例,并打印出一些信息,如果重新启动Openfire 信息成功显示,恭喜你,你已经迈出一大步了!

2、实现Plugin 类和IQHandler

Plugin 类主要起到的作用是初始化和释放资源,在初始化的过程中,最重要的的注册一批IQHandler,IQHander 的作用有点类似于Spark 中的IQProvider,其实就是解析XML 文件之后,生成一些有用的实例,以供处理。下面分别给出一个Plugin 类的实例和IQProvider 的实例

GroupTreePlugin 类

/**
 * 服务器端插件类
 * 
 * @author Phoenix
 * 
 * Mar 14, 2008 11:03:11 AM
 * 
 * version 0.1
 */
public class GroupTreePlugin implements Plugin
{
    private XMPPServer server;

/*
     * (non-Javadoc)
     * 
     * @see org.jivesoftware.openfire.container.Plugin#destroyPlugin()
     */
    public void destroyPlugin()
    {

}

/*
     * (non-Javadoc)
     * 
     * @see org.jivesoftware.openfire.container.Plugin#initializePlugin(org.jivesoftware.openfire.container.PluginManager,
     *      java.io.File)
     */
    public void initializePlugin(PluginManager manager, File pluginDirectory)
    {
        PluginLog.trace("注册群组树IQ处理器");
        server = XMPPServer.getInstance();
        
        server.getIQRouter().addHandler(new GroupTreeIQHander()); //1
        server.getIQRouter().addHandler(new UserInfoIQHandler());
        server.getIQRouter().addHandler(new DelUserIQHandler());
        server.getIQRouter().addHandler(new CreateUserIQHandler());
        server.getIQRouter().addHandler(new AddGroupUserIQHandler());
        server.getIQRouter().addHandler(new SetRoleIQHandler());

}

}

上例所示,在初始化中先找到IQRouter,然后通过IQRouter 注册一批IQHandler,这些IQHander 会自动监听相应命名空间的IQ,然后进行处理;由于这个Plugin 不需要做资源释放的工作,所以在destroyPlugin() 方法中没有任何内容。具体的IQHander 类如下

GroupTreeIQHander

/**
 * 处理客户端发来的IQ,并回送结果IQ
 * 
 * @author Phoenix
 * 
 * Mar 14, 2008 4:55:33 PM
 * 
 * version 0.1
 */
public class GroupTreeIQHander extends IQHandler
{

private static final String MODULE_NAME = "group tree handler";

private static final String NAME_SPACE = "com:im:group";

private IQHandlerInfo info;

public GroupTreeIQHander()
    {
        super(MODULE_NAME);
        info = new IQHandlerInfo("gruops", NAME_SPACE);
    }

/*
     * (non-Javadoc)
     * 
     * @see org.jivesoftware.openfire.handler.IQHandler#getInfo()
     */
    @Override
    public IQHandlerInfo getInfo()
    {
        return info;
    }

/*
     * (non-Javadoc)
     * 
     * @see org.jivesoftware.openfire.handler.IQHandler#handleIQ(org.xmpp.packet.IQ)
     */
    @Override
    public IQ handleIQ(IQ packet) throws UnauthorizedException
    {
        IQ reply = IQ.createResultIQ(packet);
        Element groups = packet.getChildElement();//1
        
        if (!IQ.Type.get.equals(packet.getType()))
        {
            System.out.println("非法的请求类型");
            reply.setChildElement(groups.createCopy());
            reply.setError(PacketError.Condition.bad_request);
            return reply;
        }
        
        String userName = StringUtils.substringBefore(packet.getFrom().toString(),"@");

GroupManager.getInstance().initElement(groups,userName);
        
        reply.setChildElement(groups.createCopy());//2

System.out.println("返回的最终XML" + reply.toXML());

return reply;
    }

}

可以看到主要有两个方法,一个是getInfo() 这个方法的目的是提供要解析的命名空间,在本例中,这个IQHandler 对每个命名空间为"com:im:group" 的实例进行处理;还有一个最重要的方法:handleIQ() 该方法对包含指定命名空间的XML 进行解析,然后返回一个解析好的IQ。其实我认为,这个IQHandler 和IQ 的关系就是Controller 和Model 的关系(如果你了解MVC 的话,那么你一定知道我再说什么),只不过这里并没有指定什么View,你完全可以把IQ 当成Model 类进行理解。在这里,我用了GroupManager 进行了XML 的处理,因为我返回的IQ 内容中要从数据库读取所有群组信息,所以转交给GroupManager 进行处理,你完全可以在这个方法中进行具体的XML 处理,在这里,解析和创建新的XML 主要用到的是JDOM(如果你对Java 解析XML 有所了解,那真的太好了!)。程序//1 处主要是获取创建返回的IQ,并获取原来IQ 的子元素(用于创建我们返回的IQ);程序//2 处很关键,如果你不调用createCopy 方法,程序会出错(程序会死锁还是什么,忘记咧,不好以西)。

这就是程序的主体部分,我在这里有一个建议,能不用Openfire 原始的程序函数,就不要用它们。我的提取数据库方式都是自己写的Bean,这样有利于你自己对程序的掌控,其实更有利于快速开发(这世道不是啥都讲究敏捷么,哇哈哈)

3、打包插件

打包依然遵循二次打包的原则(如果你不了解啥叫要二次打包,请看上一篇)
这是我的ant 文件,由于Eclipse 帮我做了build 等很多工作,实际我的ant 工作就是在打包,并放入插件目录下的plugin 文件夹下

<?xml version="1.0" encoding="UTF-8"?>
<project name="IM" default="release" basedir=".">

<property name="openfire.path"
        value="E:/workspace/europa/openfire_src/target/openfire" />
    <property name="classes.dir" value="classes" />
    <property name="lib.dir" value="lib" />

<target name="jar">
        <jar jarfile="${lib.dir}/grouptreeplugin.jar" basedir="${classes.dir}" >
            <fileset dir=".">
                <include name="*.jar"/>
            </fileset>
        </jar>
        <jar jarfile="${openfire.path}/plugins/groupTreePlugin.jar">
            <fileset dir=".">
                <include name="lib/*.jar" />
                <include name="plugin.xml" />
                <include name="logo_small.gif" />
                <include name="logo_large.gif" />
                <include name="readme.html" />
                <include name="changelog.html" />
                <include name="build.xml" />
            </fileset>
        </jar>

</target>

<target name="release" depends="jar">
    </target>

</project>

好了,至此XMPP+Spark+Openfire 的插件开发三部曲彻底结束了,希望你们对这个开发流程有了系统的了解。

在此声明,你们如有问题请留言,我会挤出时间尽量回复你们的问题。如果我不小心忘记了,请原谅我,因为现实生活中,我也是一个大忙人。我会尽量给你们回信,还有请使用email 的方式联系我,我会把我知道的内容发到你们的信箱中,还有,告诉你们一个事实,其实我很菜的,年龄也不大,别把我叫老啦!

转载于:https://blog.51cto.com/yerik/1158333

开发你自己的XMPP 续 - Openfire 插件开发相关推荐

  1. Android基于XMPP Smack openfire 开发的聊天室

    公司刚好让做即时通讯模块,服务器使用openfire,偶然看到有位仁兄的帖子,拷贝过来细细研究,感谢此仁兄的无私,期待此仁兄的下次更新 转自http://blog.csdn.net/lnb333666 ...

  2. openfire 插件开发

    1. 在上一篇博文中,我介绍了Openfire3.9.3源代码导入eclipse中开发配置指南后,在这篇博文中,我介绍一下openfire插件的开发,因为在很多使用openfire的过程中,需要更改o ...

  3. ASP.NET3.5 企业级项目开发 -- 第二章(续) 数据访问层(DAL)的开发解决方案提出...

    ASP.NET3.5 企业级项目开发 -- 第二章(续) 数据访问层(DAL)的开发解决方案提出 前言:首先给大家说声"对不起",因为自从打算写这系列的文章以来,得到大家很多的支持 ...

  4. XMPPFrameWork IOS 开发(一)xmpp简介

    原始地址:XMPPFrameWork IOS 开发(一) XMPP : The Extensible Messaging and Presence Protocol 中文全称: 可扩展通讯和表示协议 ...

  5. 【Unity】动作游戏开发实战详细分析-07-连续技与组合技功能设计

    [Unity]动作游戏开发实战详细分析-07-连续技与组合技功能设计 基本思路 在一些动作游戏中,存在着连续技这一功能,具体来说就是连续按下规定的按键会触发能力的功能,或者是长按触发等等. 实现解析 ...

  6. Android基于XMPP Smack Openfire开发IM(5)发送消息

    这节到重点了,看看发送消息的实现,代码写的很简单,主要为了演示功能的实现, 废话不说了. 在登陆以后应该建立一个监听消息的监听器,用来监听收到的消息: 这里收到消息后,通过广播将消息发送到需要的地方, ...

  7. Android基于XMPP Smack Openfire下学习开发IM(二)对分组、好友和头像等一些操作

    下面就一起来学习一下,如何查询分组和添加分组等! 一.查询所有分组 通过Roster来获取所有分组,Roster可以通过connection.getRoster()来得到. /*** 获取所有组* * ...

  8. Openfire插件开发

    注意: Openfire生成插件的jar不是像Spark一样通过build.xml生成 而是在命令行 ant plugins 实现生成插件的 这篇生成插件的方法很好 我看到最好的 http://blo ...

  9. xmpp with openfire之一 xmpp and openfire

    XMPP   百度百科 1.什么是XMPP ? XMPP(可扩展消息处理现场协议)是基于可扩展标记语言(XML)的协议,它用于即时消息(IM)以及在线现场探测.它在促进服务器之间的准即时操作.这个协议 ...

  10. openfire 插件开发例子

    2019独角兽企业重金招聘Python工程师标准>>> 好久都没有写东西了.今天总结一下之前开发的一些openfire插件. 这次的插件需要提供一个HTTP的接口.通过HTTP来对o ...

最新文章

  1. 使用json-lib实现json to javabean
  2. MFC连接MySQL C API方法
  3. 八十三、React简书项目:Styled-Components 与 Reset.css 的结合使用,完成Header布局
  4. 2017 Google 开发者大会直播入口
  5. python中括号的作用_Python3--中括号[]与冒号:在列表中的作用
  6. 当面试官问我————Java是值传递还是引用传递?
  7. 使用 docker 搭建 nginx+php-fpm 环境 (两个独立镜像)
  8. 文件夹在哪里_在Mac电脑上截图和照片放在哪里?
  9. Python获取照片信息
  10. Android拍照与相册选取图片
  11. 【PID优化】基于布谷鸟算法PID控制器优化设计含Matlab源码
  12. android获取屏幕像素密度DPI,与density
  13. android 剪切并上传图片
  14. IT资讯---------查看文章
  15. mysql 分区 线性hash_MySQL表分区(3)哈希分区-hash
  16. 互联网应用 zzl复习版
  17. 苹果 iOS 15 正式发布
  18. 通信原理及系统系列31——DOA(AOA)原理分析及仿真
  19. tp-link tl-wr740n 虚拟服务器,TPlinktl-wr740n服务器无响应,路由器上的广域网信号? 爱问知识人...
  20. 运维工程师 常见的 trouble shooting 故障排错思路

热门文章

  1. 前端为什么有的接口明明是成功回调却执行了.catch失败回调_前端战五渣学JavaScript——Promise...
  2. 思科交换机(cisco)开启802.1x认证
  3. 八个小技巧教你做出舒服的MG动画
  4. 能力提升综合题单Part 8.9.3 费用流
  5. 面试必掌握的redis的问题
  6. 238.除自身以外数组的乘积 (力扣leetcode) 博主可答疑该问题
  7. 情侣的网站代码java_GitHub - Mutiantian/lovers-website: 程序员的情侣网站 (programmer's website of lovers)...
  8. Mysql事务,并发问题,锁机制
  9. Redis学习笔记三:多机数据库的实现
  10. Python中的strip(),lstrip(),rstrip()的用法