openfire学习笔记(零)搜集资料在学习之前

ps:这是一篇无耻的资料整合笔记。

整体观感

Openfire源码目录结构

1.build目录:build目录下收录的是生成安装文件(例如:rpm)所要的一些文件,例如JRE等;
2.resources目录:resources目录下收录的是一些为实现国际化(i18n)和本地化的一些编码文件(例如:英文,中文,法文,德文等);

3.documentation目录:documentation目录下收录的是一些关于Openfire安装和配置的信息,但最终要的是这里有Openfire开发的Javado;

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对象。以便调用dispatchEvent(String property, EventType eventType, Map 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方法的第二个参数是新创建的一个ClientConnectionHandler的实例,而它就是ConnectionHandler的一个子类。

系统配置项

Openfire的系统配置项采用文件结合数据库表的方式配置,也有部分默认配置项通过Java硬编码方式配置(如org.jivesoftware.openfire. ConnectionManager接口类中定义的DEFAULT_PORT、DEFAULT_SSL_PORT、DEFAULT_COMPONENT_PORT等),Openfire中比较重要的配置位置包括:

  1. src/conf目录下的openfire.xml配置文件。该配置文件为系统核心配置文件。在第一次启动Openfire并通过管理控制台完成安装配置后会往该配置文件中填入相应的配置信息;
  2. plugin.xml配置文件。该配置文件为各插件包下的核心配置文件,由它确定插件核心处理类和相应页面插件的展现等。配置项及含义详见官方插件开发说明部分;
  3. web.xml和web-custom.xml配置文件。用于配置servlet和用户自定义servlet(插件页面用,放在插件对应目录下);
  4. ofproperty中的各条记录,该表中包括两个字段name和propvalue,分别代表配置项名和配置项值。

关于MINA

MINA是Apache组织下的一个项目,它可以帮助用户轻松的开发高性能和高扩展性的网络应用。MINA提供了一个抽象的、支持各种传输协议的(如TCP/IP、UDP/IP)、基于Java NIO的异步事件驱动的API。



MINA 的架构图 from 使用 Apache MINA 开发高性能网络应用程序

Openfire的ConnectionHandler类继承了MINA的IoHandlerAdaper,他主要负责连接的创建、销毁,以及接收到XML数据包的投递。ConnectionHandler有三个子类,其中ClientConnectionHandler负责客户端与服务器端的连接,ComponentConnectionHandler负责组件与服务器端的连接。

具体实现部分

客户端

Openfire的socket网络连接包括:

  1. 服务器和服务器之间的连接(监听在端口5269);
  2. 外部组件和服务器之间的连接(监听在端口5275);
  3. 多元(complex)连接(监听在端口5269);
  4. 客户端和服务器的连接(监听在端口5222);
  5. 和客户端通过TLS/SSL3.0和服务器的连接。(监听在端口5223);


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

客户端和服务器的连接

在ConnectionManagerImpl中是通过调用startClientListeners方法来初始化和开始端口监听的。
在startClientListeners方法使用的是Apache的Mina框架来实现网络连接的,Mina框架的模式如下:

IoFilter:

IoFilter为MINA的功能扩展提供了接口。它拦截所有的IO事件进行事件的预处理和后处理。它与Servlet中的filter机制十分相似。多个IoFilter存放在IoFilterChain中
IoFilter能够实现以下功能:
1.数据转换;

2.事件日志;

3.性能检测;

在Openfire中主要用filter(过虐器)这种机制来进行数据转换。

Protocol Codec Factory:

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

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

IoHandler:

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

sessionOpened;

sessionClosed;

sessionIdle;

exceptionCaught;

messageReceived;

messageSent;

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

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

IOSession

Session可以理解为服务器与客户端的特定连接,该连接由服务器地址、端口以及客户端地址、端口来决定。客户端发起请求时,指定服务器地址和端口,客户端也会指定或者根据网络路由信息自动指定一个地址、自动分配一个端口。这个地址、端口对构成一个Session。

客户端连接的处理过程:

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

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

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进行处理;

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

StanzaHander首先判断xml数据包的类型,.如果数据包以“
4、PacketRouteImpl中包将进一步被细化处理。

PacketRouteImp1将packet分成Message、Iq和Presence,分别交由MessageRouter、IqRouter和PresenceRouter进行下一步路由。

MessageRoute处理

调用routetableImp1进行处理,然后交由通过getRoute方法获取session,最后调用NIOConnection的deliver方法。

IQRoute 处理

根据IQ的不同的命名空间通过getHandler方法找到相应的iq处理方法进行处理。
注意:在IQRouter的initialize方法中,iqHandlers.addAll方法会将iq的命名空间与其对应的处理方法存储到一个map中。

PresenceRoute处理

调用PresenceUpdateHandler的process方法(处理数据库的更新和缓存的更新),然后调用Roster的boradcastPresence方法(检查privacy list(隐身及黑名单用户)然后路由给所有在线好友),再调用routeTable的getRoutes()获取session,最后调用NIOConnection的deliver方法。

数据库处理

Openfire的数据库处理采用直接调用JDBC 的方式。核心类为org.jivesoftware.database.DbConnectionManager。数据库的处理与业务处理耦合,没有划分出专门的业务逻辑层。

ConnectionProvider
此类为数据库提供者接口,如需连接mysql、hsqldb等数据库,需首先实现些接口。
处理方式

首先获得GroupManager的一个实例,在调用其构造函数时调用initProvider()方法,在该方法中获取数据库中配置项的值,若不为空则根据该值通过反射机制获取GroupProvider接口的实现类实例对象。

常用类

org.jivesoftware.database.DbConnectionManager
——连接管理类

org.jivesoftware.util.JiveGlobals
——通常用于操作ofproperty表中记录

感谢您赏个荷包蛋~