即时通讯 XMPP IM (二)Spark 插件开发

本文详细介绍了如何使用Spark的插件架构在IM客户端中新增功能,通过创建插件配置文件、实现自定义插件类、打包插件及部署插件等步骤,实现了获取服务器端群组信息的功能。重点讲解了插件开发流程,包括插件配置文件的编写、实现Plugin类、打包插件及部署插件的全过程。
如何基于Spark 的插件架构来新增客户端的功能,这里列举出一个获取服务器端群组信息的实际例子,实现后的效果如下图所示:

[img]http://dl.iteye.com/upload/attachment/223047/3d8c2707-2910-3091-a15a-b2dd7135177e.bmp[/img]


Spark 是一个基于XMPP 协议,用Java 实现的IM 客户端。它提供了一些API,可以采用插件机制进行扩展,上图中,“部门”部分就是使用插件机制扩展出来的新功能。要想实现你的扩展,首先要了解 Spark API的架构,其中最关键的是要了解它的工厂类,这些工厂类可以获得Spark 提供的诸如XMPPConnection、ChatContainer 等实例,从而你可以实现获取服务器的信息,与另外的Client 通信等功能。最核心的类是SparkManager,这个类是一系列工厂类的工厂类(呵呵,还真拗口)。它的getChatManager()、getSessionManager ()、getMainWindow() 、getConnection() 等方法分别可以获得聊天管理器、会话管理器、主窗口、与服务器的连接等等非常有用的实例。基本上可以说SparkManager 是你与Spark 打交道的衔接口。其实,每一个Manager 都使用了单例模式,你也可以不通过SparkManager 来获取它们,但笔者建议你从单一的入口着手,这样有利于代码的开发和维护。

接下来描述一下插件的开发流程:
1、创建插件配置文件 plugin.xml
2、实现你自己的Plugin 类的实现(如果你需要实现自己规定格式的XML 发送、接收和处理,那么你需要在这里注册你的IQProvider,关于IQProvider 你可以查询Smack API,简单的来讲是处理你自定义的IQ 处理器。)
3、打包你的插件(Spark 有自己的打包机制,我研究了半天才发现其中的玄机,后面介绍)
4、部署你的插件(其实3、4两步可以糅合在一起,当然要利用Ant 啦)

好滴,下面结合一个实际的例子讲述上面的四个步骤
1、plugin.xml

<plugin>
<name>Enterprise IM Client</name>
<version>1.0</version>
<author>Phoenix</author>
<homePage>http://phoenixtoday.blogbus.com</homePage>
<email>phoenixtoday@gmail.com</email>
<description>Enterprise Client Plug-in</description>
<!-- 关键是这里,这里要定义你的Plugin 类 -->
<class>com.im.plugin.IMPlugin</class>
<!-- 这里定义你使用的Spark 最低版本 -->
<minSparkVersion>2.5.0</minSparkVersion>
<os>Windows</os>
</plugin>

这是一个 plugin.xml 文件的内容,插件体系会自动调用你在此文件中定义的Plugin 类,从而完成你自己扩展的功能。最关键的部分我用红色标识出来了,要声明你的插件扩展类,采用完整的命名空间方式(包括包名),其余的部分结合我的注释,大家应该都能理解,就不做详细的描述了。要注意的是plugin.xml 文件要放在项目的根目录下,这是严格规定好的。

2、Plugin 类的实现
你的类首先要实现Spark 提供的Plugin 接口,然后实现它的一些方法。其中最主要的是实现initialize() 发放,在这里注册你的的IQProvider

ProviderManager providerManager = ProviderManager.getInstance();
providerManager.addIQProvider("groups", "com:im:group", //1
new GroupTreeIQProvider());
System.out.println("注册GroupTree IQ 提供者");
requestGroupTree();

上述的代码,就在该类就是我实现的IMPlugin.initialize() 方法中的一小段,大概的含义是,先获取ProviderManager(这个貌似不能从SparkManager 直接获取),然后注册一个GroupTreeIQProvider(自己创建的)这是一个IQProvider 的具体实现,它用于解析像下面这样的一个XML 文件:

<?xml version="1.0" encoding="UTF-8"?>
<iq type='result' to='domain@server.com' from='phoenixtoday@gmail.com' id='request_1'>
<groups xmlns='com:im:group'>
<group>
<groupId>1</groupId>
<name>西安交通大学</name>
<upGroup>ROOT</upGroup>
<isLeaf>0</isLeaf>
<description>xjtu</description>
<user>
<userGroupId>1</userGroupId>
<userName>phoenix_test</userName>
<role>normal</role>
</user>
</group>
<group>
<groupId>2</groupId>
<name>电信学院</name>
<upGroup>1</upGroup>
<isLeaf>1</isLeaf>
<description>xjtu info</description>
</group>
</groups>
</iq>

可以看到,在注册 IQProvider 的时候(代码中标注的1部分),需要你提供名称和命名空间,我的XML 文件中的iq 下的第一个子节点是<groups> 所以我的名称就写“groups”,命名空间对应于groups 节点的xmlns(XML Name Space)所以是“com:im:group”,其实IQProvider 中最关键的方法是parseIQ(XmlPullParser parser) 该方法就是解析XML,完成你的功能,并返回一个相应的IQ 实例(这里可以把IQ 看做一个回馈的Model 类)。说到底实现基于XMPP 协议的IM 就是解析XML 文件,而这正是客户端的IQProvider 和服务器端的IQHandler(下一篇文章会涉及到)所做的事情。

3、打包你的插件
现在该有的功能都实现了,那么就是打包了。这最好利用Ant 来完成,因为每次你都要打包,要部署,如果纯手动的话,那也太不敏捷了,大大影响开发效率。

<?xml version="1.0" encoding="UTF-8"?>
<project name="IM" default="release" basedir=".">
<property name="src.dir" value="src" />
<property name="dest.dir" value="bin" />
<property name="lib.dir" value="lib" />
<property name="im.path"
value="E:/workspace/europa/spark_new/doc/spark/target/build" />
<target name="clean">
<!--
<delete dir="${dest.dir}" />

<delete dir="${lib.dir}" />
-->
</target>
<target name="init" depends="clean">
<!--
<mkdir dir="${dest.dir}" />

<mkdir dir="${lib.dir}" />
-->
</target>
<target name="build" depends="init">
<!--
<javac srcdir="${src.dir}" destdir="${dest.dir}" />
-->
</target>
<!-- 最重要的是这里,打两次包 -->
<target name="jar" depends="build">
<jar jarfile="${lib.dir}/eim.jar" basedir="${dest.dir}" />
<jar jarfile="${im.path}/plugins/eim.jar">
<fileset dir=".">
<include name="lib/*.jar" />
</fileset>
<fileset dir=".">
<include name="plugin.xml" />
</fileset>
</jar>
</target>
<target name="release" depends="jar">
<!--
<exec executable="cmd.exe"
failonerror="true">
<arg line="/c e:"/>
<arg line="/c cd workspace\europa\spark_new\doc\spark\target\build\bin"/>
<arg line="/c startup.bat"/>
</exec>
-->
</target>
</project>

这是我的这个项目的 build.xml 文件中的内容。因为Eclipse 其实帮我自动完成了编译的任务,所以我也就省去了这写编译的步骤,最重要的是大家要看到“jar” 部分,Spark 打包的神秘之处也就在此,打两次包首先把你的项目打包到本项目lib 文件夹下,比如说你的项目目录是MyPlugin 那么,你就将你的类打包到MyPlugin/lib 目录下,然后再次的打包,将所有的lib 文件夹下的内容打包起来,记得这次要包含plugin.xml。也就是说,最后Spark 插件体系会读取你的项目下的lib 文件夹下的内容。这里我也有个疑问,我本来想每次打包后自动执行bat 文件,启动插件,看看效果,为啥死都调用不了呢,那段代码在最后面,注释掉了,谁能帮我解决,我请他吃饭滴!

4、最后就是发布了

其实我的发布很简单,就是将这个打包好的jar 文件拷到Spark 本身的plugins 目录下,每次启动Spark 的时候,它会自动调用自定义的插件的。我这里用Ant 第二次jar 的时候,就自动拷贝过去了,这里用的是绝对路径,所以你不能直接拷贝就用滴呦(是不是很丑陋呀,这段Ant 代码)。

基本上客户端的实现原理就是这样的,只是有些地方需要特别注意,还有就是应该利用像Ant 这样的工具大大简化开发步骤,加快开发效率。还有就是,我建议你在开发自己的插件的时候,多利用MVC 模式,尤其是在IQProvider 解析后,生成的部分可以实例化Model,然后你可以编写自己的Manager 进行这些Model 的处理。多写Log,当然Log4j 貌似不太起作用,那就System.out.println() 吧,哈哈!今天就写到这里啦,偶有点累啦。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值