Openfire源码研究
 Openfire源码目录结构
1.build目录:build目录下收录的是生成安装文件(例如:rpm)所要的一些文件,例如JRE等。
2.resources目录:resources目录下收录的是一些为实现国际化(i18n)和本地化的一些编码文件(例如:英文,中文,法文,德文等)。
3.documentation目录:documentation目录下收录的是一些关于Openfire安装和配置的信息,但最终要的是这里有Openfire开发的Javadoc
4.src目录:顾名思义这个src文件夹就是我们想要的Openfire源代码了,这下面又有许多文件夹,我们只要Java文件夹就好,这里面实现的Openfire的核心功能,通过它就可以调试Openfire了。
命名规则
Openfire中常见的类名后缀命名包括Starter、Plugin、Listener、Dispatcher、Handler、Manager、Provider,通常情况下,这些命名类包括如下意义:
XXStarter
系统启动类,如org.jivesoftware.openfire.starter.ServerStarter,调用其start()方法可启动系统应用。
XXListener
业务的最终处理类。
XXDispatcher
调度类,其中有很多关键方法,如addListener(),以组合的方式,为类内定义的静态Set<XXListener>实例添加XXListener对象。以便调用dispatchEvent(String property, EventType eventType, Map<String, Object> params)方法遍历处理Set集中的XXListener对象(通过调用XXListener对象的各实际方法完成实际业务)。
XXPlugin
实现Plugin接口的插件类,需实现initializePlugin(PluginManager manager, File pluginDirectory)方法和destroyPlugin()方法。在其初始化方法中调用Dispatcher实现类的addListener()方法如PropertyEventDispatcher.addListener(this)。
XXProvider
    实现面向接口编程方式的接口类,通过反射机制创建具体实现类的对象,反射类名配置在ofproperty表对应的记录propvalue属性中。若没有相关配置,则调用默认实现类,默认实现类类名命名规则为DefaultXXProvider。
XXHandler
实际处理类,以ConnectionHandler为例,在org.jivesoftware.openfire.spi. ConnectionManagerImpl类的startClientSSLListeners(String localIPAddress)方法中,有这样一段代码:sslSocketAcceptor.bind(new InetSocketAddress(bindInterface, port), new ClientConnectionHandler(serverName));其中bind方法的第二个参数是新创建的一个ClientC
onnectionHandler的实例,而它就是ConnectionHandler的一个子类。
系统配置项
Openfire的系统配置项采用文件结合数据库表的方式配置,也有部分默认配置项通过Java硬编码方式配置(如org.jivesoftware.openfire. ConnectionManager接口类中定义的DEFAULT_PORTDEFAULT_SSL_PORTDEFAULT_COMPONENT_PORT等),Openfire中比较重要的配置位置包括:
一、 src/conf目录下的l配置文件。该配置文件为系统核心配置文件。在第一次启动Openfire并通过管理控制台完成安装配置后会往该配置文件中填入相应的配置信息。
二、 l配置文件。该配置文件为各插件包下的核心配置文件,由它确定插件核心处理类和相应页面插件的展现等。配置项及含义详见官方插件开发说明部分。
三、 ll配置文件。用于配置servlet和用户自定义servlet(插件页面用,放在插件对应目录下)
四、 ofproperty中的各条记录,该表中包括两个字段namepropvalue,分别代表配置项名和配置项值。
系统启动流程
系统启动时调用ServerStarter类中的start()方法,通过反射加载org.jivesoftware.openfire.XMPPServer类文件,创建实例时调用其构造函数,在其构造函数中调用其start()方法实际启动服务应用程序。Start()方法中首先调用verifyDataSource()方法验证并确保数据库可以访问,然后会调用                loadModules();initModules();startModules();方法来对Module接口的实现类的各子类进行操作,依次完成模块的加载、初始化和启动操作。loadModules()方法中会调用loadModule(String module)方法通过反射加载各模块类,参数字符串module为对应的模块核心处理类的类名。
客户端
Openfiresocket网络连接包括:
1.      服务器和服务器之间的连接(监听在端口5269
2.      外部组件和服务器之间的连接(监听在端口5275
3.      多元(complex)连接(监听在端口5269
4.      客户端和服务器的连接(监听在端口5222
5.      和客户端通过TLS/SSL3.0和服务器的连接。(监听在端口5223
 这些连接都是通过ConnectionManager接口实现管理的,程序中对ConnectionManager接口的实现类是ConnectionManagerImpl,它是作为一个模块(Module)类加载到服务器中的。
客户端和服务器的连接
ConnectionManagerImpl中是通过调用startClientListeners方法来初始化和开始端口监听的。
startClientListeners方法使用的是ApacheMina框架来实现网络连接的,Mina框架的模式如下:
IoFilter
IoFilterMINA的功能扩展提供了接口。它拦截所有的IO事件进行事件的预处理和后处理。它与mysql需要安装documentationServlet中的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等待客户端的连接。
IOSession
Session可以理解为服务器与客户端的特定连接,该连接由服务器地址、端口以及客户端地址、端口来决定。客户端发起请求时,指定服务器地址和端口,客户端也会指定或者根据网络路由信息自动指定一个地址、自动分配一个端口。这个地址、端口对构成一个Session。
客户端连接的处理过程:
1、当有客户端进行连接时根据Mina框架的模式首先调用的是sessionOpened方法。
sessionOpened首先为此新连接构造了一个parserXMLLightWeightParser),这个parser是专门给XMPPDecoder(是XMPPCodecFactory的解码器类)使用的,再创建一个OpenfireConnection类实例connection和一个StanzaHandler的实例。最后将以上的parser, connectionStanzaHandler的实例存放在Minasession中,以便以后使用。
2、当有数据发送过来时,Mina框架会调用messageReceived方法
messageReceived首先从Mina的session中得到在sessionOpened方法中创建的StanzaHandler实例handler,然后从parsers中得到一个parser(如果parsers中没有可以创建一个新的实例)(注意这个parser和在sessionOpened方法中创建的parser不同,这个parser是用来处理Stanza的,而在sessionOpened方法中创建的parser是在filter中用来解码的,一句话说就是在sessionOpened方法中创建的parser是更低一层的parser)。最后将xml数据包交给StanzaHander的实例hander进行处理。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。