IM即时通讯研究

openfire专题研究

BlogJava 首页 新随笔 联系 聚合 管理
  2 Posts :: 0 Stories :: 12 Comments :: 0 Trackbacks
 

openfire开发文档
版本:Openfire3.5.
作者:---------- 日期:-----------

 

一、初始工作····································2

1、安装jdk1.5

2、安装eclipse,myeclipse

3、安装oracle10gXE

4、安装openfire3.5.1源代码

二、环境配置····································

1、配置java环境

2、配置openfire运行环境

三、代码研究····································

四、功能扩展····································

五、与客户端一起调试··························


第一章:初始工作

1.1安装jdk1.5

方法1:放在F盘的安装程序的java开发工具文件夹里

    方法2:可从www.sun.com.cn下载jdk1.5.

1.2安装eclipse3.3,myeclipse6.0

    放在F盘的安装程序的java开发工具文件夹里

1.3安装oracle10gXE

    放在F盘的安装程序的java开发工具文件夹里

1.4安装openfire3.5.1源代码

    源代码的下载

方法1:放在F盘的openfire文件夹里

方法2:可从openfire的官方网站下载,网址在IE的收藏夹里

②源代码的安装

将下载好的openfire源代码解压出来,复制到eclipseworkspace里,打开eclipse,点新建java工程,在Contents里选择第二个,即Create project from existing source, Directory选项里点右边的Browse按钮,选择eclipseworkspace里的openfire文件夹(这个文件夹的名字应该叫:openfire_src),点确定。再填入Project name,工程名字一定要和eclipseworkspace里的openfire源代码的文件夹名字相同,如下图所示:

点击完成,即成功导入openfire源代码到eclipse中。如下图所示:

右击工程,点属性->Java Build Path ->Libraries加入所对应的测试jar包,叫test什么什么的,放在E盘里。点击完成,即可将错误消除。

第二章:环境配置

2.1、配置java环境

    我的电脑点右键,选择“属性”。

选择“高级”标签。

进入环境变量设置:

分别设置如下三个环境变量:
PATH=C:"jdk1.6.0"bin
CLASSPATH=.;%JAVA_HOME%"lib"tools.jar;%JAVA_HOME%"lib"dt.jar(注意,CLASSPATH最前面是有个“.”的,表示当前目录)
JAVA_HOME=C:"jdk1.6.0

设置完成之后,我们来测试一下。开始-》运行,输入“CMD”,回车。

在打开的DOS命令窗口中输入“java -version”,回车。

如果能像上图那样显示JDK的版本,说明“PATH”变量设置没有问题,如果有问题,检查PATH变量设置,输入“echo %PATH%”。

看其中是否存在“C:"jdk1.6.0"bin”。如果不存在则返回到环境变量设置中检查。

接下来我们编写一个简单的Java程序测试CLASSPATH是否设置正确。

打开记事本,输入下面的内容,保存至C:"java目录下,文件名为HelloWorld.java。(注意大小写)

class HelloWorld{
public static void main(String[] arg){
System.out.println("HelloWorld");
}
}

在打开的DOS命令窗口,进入C:"java,输入“java HelloWorld.java”,回车。

这时在C:"java目录下多了一个“HelloWorld.class”的文件。

在打开DOS命令窗口,输入“java HelloWorld”,回车。

如果程序没错,那么将输出“HelloWorld”。

恭喜,你的Java环境配置成功了。

2.2、配置openfire运行环境

    点击运行按钮旁边的小的黑色三角,点击Open Run Dialog…

出现如下窗口,双击Java Application,Name框里的名字改成:openfire_src3.5.1,点击Main class右边的Search按钮,

 

 

出现如下窗口:

在第一个文本框里输入server,在第二个框里选择ServerStarter-org.jivesoftware.openfire.starter,点OK

 

点击eclipse菜单Window->Show View->Ant,如图:

 

ant窗口里右击选择Add Buildfiles…,如下图所示:

 

出现如下窗口:选择:openfire_src->build->build.xml,点击OK按钮。

 

双击在ant窗口里生成的菜单,即开始部署项目。

 

察看console里显示的信息:如果显示BUILD SUCCESSFUL就表示项目部署成功。如图:

 

 

第三章:代码研究

Openfiresocket网络连接包括:

<!--[if !supportLists]-->1.       <!--[endif]-->服务器和服务器之间的连接(监听在端口5269

<!--[if !supportLists]-->2.       <!--[endif]-->外部组件和服务器之间的连接(监听在端口5275

<!--[if !supportLists]-->3.       <!--[endif]-->多元(complex)连接(监听在端口5269

<!--[if !supportLists]-->4.       <!--[endif]-->客户端和服务器的连接(监听在端口5222

<!--[if !supportLists]-->5.       <!--[endif]-->和客户端通过TLS/SSL3.0和服务器的连接。(监听在端口5223

这些连接都是通过ConnectionManager接口实现管理的,程序中对ConnectionManager接口的实现类是ConnectionManagerImpl,它是作为一个模块(Module)类加载到服务器中的。

下面分析的是客户端和服务器的连接。

 

ConnectionManagerImpl中是通过调用startClientListeners方法来初始化和开始端口监听的。

Mina框架<!--[endif]-->startClientListeners方法使用的是ApacheMina框架来实现网络连接的,Mina框架的模式如下:

IoFilter

       IoFilterMINA的功能扩展提供了接口。它拦截所有的IO事件进行事件的预处理和后处理。它与Servlet中的filter机制十分相似。多个IoFilter存放在IoFilterChain

       IoFilter能够实现以下功能:

              数据转换

              事件日志

              性能检测

       Openfire中主要用filter这种机制来进行数据转换。

Protocol Codec Factory

       Protocol Codec Factory提供了方便的Protocol支持,通过它的EncoderDecoder,可以方便的扩展并支持各种基于Socket的网络协议,比如HTTP服务器、FTP服务器、Telnet服务器等等。

       要实现自己的编码/解码器(codec)只需要实现interface: ProtocolCodecFactory即可,在Openfire中实现ProtocolCodecFactory的类为XMPPCodecFactory

IoHandler:

    MINA中,所有的业务逻辑都有实现了IoHandlerclass完成    ,当事件发生时,将触发IoHandler中的方法:

           sessionCreated

sessionOpened

sessionClosed

sessionIdle

exceptionCaught

messageReceived

messageSent

       Openfire中客户端和服务器连接的IoHandler实现类是ClientConnectionHandler,它是从ConnectionHandler中继承来的。

startClientListeners方法首先为Mian框架设置线程池,再将一个由XMPPCodecFactory作为Protocol Codec FactoryFilter放入到FilterChain中,然后绑定到端口5222,并将ClientConnectionHandler作为IoHandler对数据进行处理。完成这些步骤后Openfire就在5222等待客户端的连接。

客户端连接的处理过程:

 

当有客户端进行连接时根据Mina框架的模式首先调用的是sessionOpened方法。

       sessionOpened首先为此新连接构造了一个parserXMLLightWeightParser),这个parser是专门给XMPPDecoder(是XMPPCodecFactory的解码器类)使用的,再创建一个OpenfireConnection类实例connection和一个StanzaHandler的实例。最后将以上的parser, connectionStanzaHandler的实例存放在Minasession中,以便以后使用。

       当有数据发送过来时,Mina框架会调用messageReceived方法

       messageReceived首先从Minasession中得到在sessionOpened方法中创建的StanzaHandler实例handler,然后从parsers中得到一个parser(如果parsers中没有可以创建一个新的实例)(注意这个parser和在sessionOpened方法中创建的parser不同,这个parser是用来处理Stanza的,而在sessionOpened方法中创建的parser是在filter中用来解码的,一句话说就是在sessionOpened方法中创建的parser是更低一层的parser)。最后将xml数据包交给StanzaHander的实例hander进行处理。

       StanzaHander的实例hander处理xml数据包的过程

       StanzaHander首先判断xml数据包的类型,.如果数据包以“<stream:stream”打头那么说明客户端刚刚连接,需要初始化通信(符合XMPP协议)Openfire首先为此客户端建立一个与客户端JID相关的ClientSession,而后与客户端交互协商例如是否使用SSL,是否使用压缩等问题。当协商完成之后进入正常通信阶段,则可以将xml数据包交给这个用户的ClientSession进行派送(deliever),经过派送数据包可以发送给PacketRouteImpl模块进行处理。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

第四章:功能扩展

4.1修改源代码

    用户的创建。由于源代码中用户信息不能满足要求,需要扩展。服务器端创建用户比较简单,主要是客户端的创建比较复杂,主要有4个步骤,客户端发送创建用户的请求(get请求),请求创建的用户字段,服务器端接收到之后进行过滤,然后返回信息(result),信息中只包含合法的用户属性,客户端收到之后,再将合法的用户字段发送给服务器(set请求),服务器再根据收到的用户字段创建用户,即写入数据库。

用户的查询。过程类似上面用户的创建。

4.2插件开发

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
类主要起到的作用是初始化和释放资源,在初始化的过程中,最重要的的注册一批IQHandlerIQHander 的作用有点类似于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>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

第五章:与客户端一起调试

5.1debug模式启动服务器,根据客户端的需要在相应位置设置端点,分析数据。

posted on 2009-02-10 12:40 gissing 阅读(13800) 评论(5)  编辑  收藏

Feedback

# re: openfire开发文档 2009-04-06 01:28 三毛不再流浪
好!!  回复  更多评论
  

# re: openfire开发文档 2009-06-29 21:39 钱奕

研究小组:
您们好!
我现在安装配置openfire时出现一些障碍,想请高手支招。

我是一个完全不懂程序的人,呵呵,openfire+spark程序在本地电脑上调试一切正常,可是不知道为什么远程服务器的时候链接数据库总是失败。
提示:The Openfire database schema does not appear to be installed. Follow the installation guide to fix this error.
我用的是MSSQL,localhost/数据库名称,用户名和密码都正确的,但总是过不去这一关,不知是何原因。急急急…………

我的QQ:70734260(输赢) 帮帮忙,呵呵  回复  更多评论
  

# re: openfire开发文档 2009-07-14 17:08 小生有礼
搞openfire 研究已有一段时间,但总不知道从何下手,手上资料也没有,一般都是在网上找资料,还请高手指点迷经,在下不胜感激。  回复  更多评论
  

# re: openfire开发文档 2009-09-29 11:52 EricLee
你的远程服务器建数据库没有啊,我记得openfire需要手动建立数据库的。  回复  更多评论
  

# re: openfire开发文档 2012-09-19 13:41 kp.wang
很好的学习资料  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: