OpenFire简介

来源:互联网 发布:淘宝店铺装修设计师 编辑:程序博客网 时间:2024/06/06 04:33


  • 1基础简介
  • XMPP
  • IM
  • Spark Smack 和 Openfire
  • Apache MINA
  • 2命名规则
  • XXStarter
  • XXListener
  • XXDispatcher
  • XXPlugin
  • XXProvider
  • XXHandler
  • 3系统配置项
  • 4系统启动流程
  • 5网络处理
  • 消息监听服务
  • 消息封装
  • Openfire消息包接受处理流程
  • 6数据库处理
  • ConnectionProvider
  • 处理方式
  • 常用类
  • openfire数据结构
  • 7WEB服务器
  • 8页面处理
  • 9插件开发
  • Openfire Plugins加载流程
  • 官方插件开发说明

1基础简介

XMPP

Extensible Messaging and Presence Protocol,简单的来讲,它就是一个发送接收处理消息的协议,但是这个协议发送的消息,既不是二进制的东东也不是字符串,而是XML。正是因为使用了XML作为消息传递的中介,Extensible 才谈的上,不是么?

IM

Instant Messenger,及时通信软件,就是大家使用的QQ、MSN Messenger和Gtalk等等。其中Gtalk 就是基于XMPP 协议的一个实现,其他的则不是。当前IM 几乎作为每个上网者必然使用的工具,在国外的大型企业中有一些企业级的IM应用,但是其商业价值还没完全发挥出来。设想既然XMPP 协议是一个公开的协议,那么每个企业都可以利用它来开发适合本身企业工作,提高自身生产效率的IM;甚至,你还可以在网络游戏中集成这种通信软件,不但让你可以边游戏边聊天,也可以开发出适合游戏本身的IM 应用,比如说一些游戏关键场景提醒功能,团队语音交流等等都可以基于IM来实现。

Spark Smack 和 Openfire

开源界总是有许多有趣的东东,这三个合起来就是一个完整的XMPP IM 实现。包括服务器端——Openfire,客户端——Spark,XMPP 传输协议的实现——Smack(记住,XMPP是一个协议,协议是需要实现的,Smack起到的就是这样的一个作用)。三者都是基于Java 语言的实现。

Spark 提供了客户端一个基本的实现,并提出了一个很好的插件架构,这对于开发者来说不能不说是一个福音。我强烈建议基于插件方式来实现你新增加的功能,而不是去改它的源代码,这样有利于你项目架构,把原始项目的影响降到最低。

Openfire 是基于XMPP 协议的IM 的服务器端的一个实现,虽然当两个用户连接后,可以通过点对点的方式来发送消息,但是用户还是需要连接到服务器来获取一些连接信息和通信信息的,所以服务器端是必须要实现的。Openfire 也提供了一些基本功能,但真的很基本的!庆幸的是,它也提供插件的扩展,像Spark 一样,同样强烈建议使用插件扩展的方式来增加新的功能,而不是修改人家的源代码。

Smack 是一个XMPP 协议的Java 实现,提供一套可扩展的API,不过有些时候,你还是不得不使用自己定制发送的XML 文件内容的方式来实现自己的功能

企业案例-聚友中国即时通讯-PC端+WEB端+android端+ios端+平板端+云端多平台互通、方便集成各类应用

 

下图展示了三者之间的关系: 

 图片

 

 

 

从图上可以了解到,client 端和server端都可以通过插件的方式来进行扩展,smack是二者传递数据的媒介。

Apache MINA

Openfire的通信处理基于Apache MINA框架实现。Apache MINA是一个网络应用程序框架,用来帮助用户简单地开发高性能和高可靠性的网络应用程序。它提供了一个通过Java NIO在不同的传输例如TCP/IP和UDP/IP上抽象的事件驱动的异步API。

  Apache MINA 也称为:

  ● NIO 框架库

  ● 客户端服务器框架库

  ● 一个网络套接字库

  MINA虽然简单但是仍然提供了全功能的网络应用程序框架:

  ● 为不同的传输类型提供了统一的API:

  ○ 通过Java NIO提供TCP/IP 和 UDP/IP支持

  ○ 通过RXTX提供串口通讯(RS232)

  ○ In-VM管道通讯

  ○ 你能实现你自己的API!

  ● 过滤器作为一个扩展特性; 类似Servlet过滤器

  ● 低级和高级的API:

  ○ 低级: 使用字节缓存(ByteBuffers)

  ○ 高级: 使用用户定义的消息对象(objects)和编码(codecs)

  ● 高度定制化线程模型:

  ○ 单线程

  ○ 一个线程池

  ○ 一个以上的线程池(也就是SEDA)

  ● 使用Java 5 SSL引擎提供沙盒(Out-of-the-box) SSL • TLS • StartTLS支持

  ● 超载保护和传输流量控制

  ● 利用模拟对象进行单元测试

  ● JMX管理能力

  ● 通过StreamIoHandler提供基于流的I/O支持

  ● 和知名的容器(例如PicoContainer、Spring)集成

  ● 从Netty平滑的迁移到MINA, Netty是MINA的前辈。

2命名规则

Openfire中常见的类名后缀命名包括Starter、Plugin、Listener、Dispatcher、Handler、Manager、Provider,通常情况下,这些命名类包括如下意义:

XXStarter

系统启动类,如org.jivesoftware.openfire.starter.ServerStarter,调用其start()方法可启动系统应用。

XXListener

业务的最终处理类。

 

所有的业务都是在Listener类中实现的

 

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方法的第二个参数是新创建的一个ClientConnectionHandler的实例,而它就是ConnectionHandler的一个子类。

3系统配置项

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

一、     src/conf目录下的openfire.xml配置文件。该配置文件为系统核心配置文件。在第一次启动Openfire并通过管理控制台完成安装配置后会往该配置文件中填入相应的配置信息。

二、     plugin.xml配置文件。该配置文件为各插件包下的核心配置文件,由它确定插件核心处理类和相应页面插件的展现等。配置项及含义详见官方插件开发说明部分。

三、     web.xml和web-custom.xml配置文件。用于配置servlet和用户自定义servlet(插件页面用,放在插件对应目录下)。

四、     ofproperty中的各条记录,该表中包括两个字段name和propvalue,分别代表配置项名和配置项值。

 

4系统启动流程

    系统启动时调用ServerStarter类中的start()方法,通过反射加载org.jivesoftware.openfire.XMPPServer类文件,创建实例时调用其构造函数,在其构造函数中调用其start()方法实际启动服务应用程序。Start()方法中首先调用verifyDataSource()方法验证并确保数据库可以访问,然后会调用                loadModules();initModules();startModules();方法来对Module接口的实现类的各子类进行操作,依次完成模块的加载、初始化和启动操作。loadModules()方法中会调用loadModule(String module)方法通过反射加载各模块类,参数字符串module为对应的模块核心处理类的类名,如AdHocCommandHandler。现以AdHocCommandHandler为例对接下来的处理流程进行说明。通过loadModule创建AdHocCommandHandler类实例时调用其构造函数,在构造函数中初始化了其私有AdHocCommandManager对象。在initModules()时调用AdHocCommandHandler实例的initialize(XMPPServer server)方法对其私有属性对象进行初始化。然后调用start()方法,调用addDefaultCommands方法添加命令并启动命令(通过调用startCommand(AdHocCommand command)方法实现)。

5网络处理

消息监听服务

SSL等监听服务的调度在ConnectionManagerImpl类中实现。ConnectionManagerImpl.createClientSSLListeners()方法启动SSL监听

 

消息封装

信息处理采用XML节的方式传递信息,消息封装通常采用IQ、Message、Presence。

Openfire消息包接受处理流程

 

6数据库处理

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

ConnectionProvider

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

处理方式

    通常直接调用XXManager中的实例方法,XXManager中又调用的是对应的接口XXProvider的方法,实际操作在该接口的实现类中实现。实现类是动态绑定的(默认的实现类通常命名规则为DefaultXXProvider),在运行时根据ofproperty表中对应配置项值选择。下面以添加用户组为例进行说明。

    首先获得GroupManager的一个实例,在调用其构造函数时调用initProvider()方法,在该方法中获取数据库中配置项的值,若不为空则根据该值通过反射机制获取GroupProvider接口的实现类实例对象;若为空则以DefaultGroupProvider作为GroupProvider接口的实现类并创建实例对象,然后调用GroupProvider. createGroup(String name)方法完成业务操作。

 

常用类

org.jivesoftware.database.DbConnectionManager

    连接管理类

 

org.jivesoftware.util.JiveGlobals

    通常用于操作ofproperty表中记录

 

openfire数据结构

数据库表

以下是一个说明每个表格的Openfire数据库架构。黄色行表示主键。

·         ofGroup

·         ofGroupProp

·         ofGroupUser

·         ofID

·         ofOffline

·         ofPresence

·         ofPrivate

·         ofUser

·         ofUserProp

·         ofUserFlag

·         ofRoster

·         ofRosterGroups

·         ofPrivacyList

·         ofVCard

·         ofVersion

·         ofProperty

·         ofExtComponentConf

·         ofRemoteServerConf

·         ofSecurityAuditLog

·         ofMucService

·         ofMucServiceProp

·         ofMucRoom

·         ofMucRoomProp

·         ofMucAffiliation

·         ofMucMember

·         ofMucConversationLog

·         ofPubsubNode

·         ofPubsubNodeJIDs

·         ofPubsubNodeGroups

·         ofPubsubAffiliation

·         ofPubsubItem

·         ofPubsubSubscription

·         ofPubsubDefaultConf

ofGroup (用户组的数据)

列名类型长度描述groupNameVARCHAR50组名称(主键)descriptionVARCHAR255组描述

 

ofGroupProp (名称值协会为一组)

列名类型长度描述groupNameVARCHAR50组名称(主键)nameVARCHAR100组属性名称(主键)propValueVARCHAR4000组,属性值

 

ofGroupUser (组成员)

列名类型长度描述groupNameVARCHAR50组名称(主键)usernameVARCHAR100用户名,(主键)administratorNUMBERn/a是否为管理员(布尔)(主键)

 

ofID (用于唯一ID序列生成)

列名类型长度描述idTypeNUMBERn/a证件类型(例如,组,用户名册)(主键)idNUMBERn/a下一个可用块编号的(用于数据库独立编号)

 

ofOffline (离线邮件存储)

列名类型长度更改usernameVARCHAR32用户名(主键)messageIDNUMBERn/a存储信息的编号(主键)creationDateVARCHAR15日期信息存储messageSizeNUMBERn/a邮件的大小以字节为单位stanzaTEXTn/a消息文本

 

ofPresence (离线的存在)

列名类型长度更改usernameVARCHAR64用户名(主键)offlinePresenceTEXTn/a存在的信息设置为用户注销offlineDateCHAR15信息存储日期

 

ofPrivate (私人数据存储)

列名类型长度描述usernameVARCHAR32用户名(主键)nameVARCHAR100姓名私营项(主键)namespaceVARCHAR200名字空间私营项(主键)privateDataTEXTn/a价值的私人数据

 

ofUser (用户数据)

列名类型长度描述usernameVARCHAR32用户名(主键)plainPasswordVARCHAR32纯文字密码数据encryptedPasswordVARCHAR255加密的密码数据(默认)nameVARCHAR100名字emailVARCHAR100电邮地址creationDateVARCHAR15创建日期modificationDateVARCHAR15最后更新日期

 

ofUserProp (名称值协会针对用户)

列名类型长度描述usernameVARCHAR32用户名(主键)nameVARCHAR100用户属性名称(主键)propValueVARCHAR4000用户属性值

 

ofUserFlag (用户类型标识(如残疾人))

列名类型长度描述usernameVARCHAR64用户名(主键)nameVARCHAR100用户属性名称(主键)startTimeCHAR15国旗的时候,开始被有效(无效的'现在',)endTimeCHAR15当时国旗是结束有效(无效的'永远',)

 

ofRoster (好友列表)

列名类型长度描述rosterIDNUMBERn/a编号,名册,(主键)usernameVARCHAR32用户名jidTEXTn/a地址名册入境subNUMBERn/a认购地位入境askNUMBERn/a卖出地位入境recvNUMBERn/a检举表明进入名册收到请求nickVARCHAR255昵称分配给这个名册入境

 

ofRosterGroups (组的好友名单中的条目)

列名类型长度描述rosterIDNUMBERn/a名册编号(主键)rankNUMBERn/a立场项(主键)groupNameVARCHAR255用户定义的名称,这个名册组

 

ofPrivacyList (用户隐私清单)

列名类型长度描述usernameVARCHAR32用户名(主键)nameVARCHAR100姓名保密清单(主键)isDefaultNUMBERn/a检举指出,如果这是默认隐私的用户名单listTEXTn/aXML表示的隐私清单

 

ofVCard (电子名片的联系信息)

列名类型长度描述usernameVARCHAR32用户名(主键)vcardTEXTn/a价值的vCard入境

 

ofVersion (包含产品版本信息)

列名类型长度描述nameVARCHAR50名称的项目,版本信息正在跟踪的(主键)versionINTEGERn/a版本号

 

ofProperty (服务器属性)

列名类型长度描述nameVARCHAR100属性名称(主键)propValueTEXTn/a进入值

 

ofExtComponentConf (外部元件配置)

列名类型长度描述subdomainVARCHAR255子的外部元件(主键)secretVARCHAR255共享,密钥,的外部元件permissionVARCHAR10许可,表明如果组件是可以连接到服务器

 

ofRemoteServerConf (远程服务器配置)

列名类型长度描述xmppDomainVARCHAR255域的外部元件(主键)remotePortNUMBERn/a港口的远程服务器连接到permissionVARCHAR10许可,表明如果远程服务器可以连接到服务器

 

ofSecurityAuditLog (伐木安全事件)

列名类型长度描述msgIDNUMBERn/a编号审计信息(主键)usernameVARCHAR64使用者谁执行的行动entryStampNUMBERn/a时间戳,当事件发生summaryVARCHAR255总结了发生在事件nodeVARCHAR255节点事件发生detailsTEXTn/a详细的细节,所发生的

 

ofMucService (甲Groupchat服务)

列名类型长度描述serviceIDNUMBERn/a编号的服务(收录)subdomainVARCHAR255子服务(主键)descriptionVARCHAR255服务说明isHiddenNUMBERn/a1,如果隐藏的管理界面名单,0正常

 

ofMucServiceProp (名称值协会的Groupchat服务)

列名类型长度描述serviceIDNUMBERn/a编号的服务(主键)nameVARCHAR100属性名称(主键)propValueTEXTn/a属性值

 

ofMucRoom ( Groupchat室内资料)

列名类型长度描述roomIDNUMBERn/a编号的房间(主键)creationDateVARCHAR15创建日期modificationDateVARCHAR15最后更新日期nameVARCHAR50姓名房间用作公共编号naturalNameVARCHAR255天然名称室descriptionVARCHAR255客房描述canChangeSubjectNUMBERn/a检举指出是否可以改变参与者的主题maxUsersNUMBERn/a马克斯一些房间居住者canChangeSubjectNUMBERn/a检举指出是否与会者可以改变的主题或不publicRoomNUMBERn/a检举指示是否室将在目录中列出或不moderatedNUMBERn/a检举指示是否室主持或不membersOnlyNUMBERn/a检举指出是否房间是会员制或不canInviteNUMBERn/a检举指出是否占用可以邀请其他用户roomPasswordVARCHAR50密码数据加入室canDiscoverJIDNUMBERn/a检举指出是否真正JID的居住者是公共或不logEnabledNUMBERn/a检举指出是否房间谈话记录或不subjectVARCHAR100最后为人所知的主题房间rolesToBroadcastNUMBERn/a二元代表的作用,以广播useReservedNickNUMBERn/a检举指出是否用户只能加入室使用其保留昵称canChangeNickNUMBERn/a检举指出是否可以改变其占用的空间昵称canRegisterNUMBERn/a检举显示用户是否被允许登记室

 

ofMucRoomProp (名称值协会的Groupchat房间)

列名类型长度描述roomIDNUMBERn/a编号的房间(主键)nameVARCHAR100属性名称(主键)propValueVARCHAR4000属性值

 

ofMucAffiliation (归属的空间用户)

列名类型长度描述roomIDNUMBERn/a编号的房间(主键)jidTEXTn/a用户JID,(主键)affiliationNUMBERn/a一些代表所属一级

 

ofMucMember (室成员资料)

列名类型长度描述roomIDNUMBERn/a编号的房间(主键)jidTEXTn/a用户JID,(主键)nicknameVARCHAR255保留昵称的会员

 

ofMucConversationLog (室会话日志)

列名类型长度描述roomIDNUMBERn/a编号的空间senderTEXTn/aJID的用户发送邮件的房间nicknameVARCHAR255昵称使用时由用户发出的信息logTimeVARCHAR15日期的消息时,被送到房间subjectVARCHAR50新的主题改变的信息bodyTEXTn/a消息正文

 

ofPubsubNode (节点pubsub服务)

列名类型长度描述serviceIDVARCHAR100编号托管服务节点(主键)nodeIDVARCHAR100编号的节点(主键)leafNUMBERn/a检举表明节点是否是叶或收集节点creationDateVARCHAR15创建日期modificationDateVARCHAR15最后更新日期parentVARCHAR100编号的父节点(如果有的话)deliverPayloadsNUMBERn/a检举指出是否有效载荷中包含的通知maxPayloadSizeNUMBERn/a最大规模的有效载荷的字节persistItemsNUMBERn/a检举表明节点是否将持续出版项目maxItemsNUMBERn/a最大的项目数量将持续notifyConfigChangesNUMBERn/a检举指出是否发送通知时,该节点的配置发生了变化notifyDeleteNUMBERn/a检举指出是否发送通知时,该节点将被删除notifyRetractNUMBERn/a检举指出是否发送通知时,发布的项目将被删除presenceBasedNUMBERn/a检举指出是否发送通知只有用户才sendItemSubscribeNUMBERn/a检举指出是否向去年出版项目,以新用户publisherModelVARCHAR15Publisher中使用的模式的节点subscriptionEnabledNUMBERn/a检举指出是否允许订阅configSubscriptionNUMBERn/a检举指出是否新的订户必须设定为活跃accessModelVARCHAR10访问模型所使用的节点payloadTypeVARCHAR100类型的有效载荷数据将提供在节点bodyXSLTVARCHAR100网址的一个XSLT转换有效载荷的格式为一个邮件正文dataformXSLTVARCHAR100网址的一个XSLT转化的有效载荷格式的数据形式结果creatorVARCHAR1024JID的实体建立了节点descriptionVARCHAR255说明节点languageVARCHAR255默认语言的节点nameVARCHAR50名称节点replyPolicyVARCHAR15政策界定业主或出版商是否应得到答复项目associationPolicyVARCHAR15政策规定谁可以联系叶节点的集合maxLeafNodesNUMBERn/a马克斯一些叶节点,一个节点可能会收集

 

ofPubsubNodeJIDs ( JIDs与节点)

列名类型长度描述serviceIDVARCHAR100编号托管服务节点(主键)nodeIDVARCHAR100编号的节点(主键)jidVARCHAR1024JID实体(主键)associationTypeVARCHAR20协会类型的节点

 

ofPubsubNodeGroups (名册集团与节点)

列名类型长度内容serviceIDVARCHAR100编号托管服务节点nodeIDVARCHAR100编号的节点rosterGroupVARCHAR100名册组节点所有者可以签署和检索项目

 

ofPubsubAffiliation (节点分支机构)

列名类型长度描述serviceIDVARCHAR100编号托管服务节点(主键)nodeIDVARCHAR100编号的节点(主键)jidVARCHAR1024JID的子公司(主键)affiliationVARCHAR10所属类别

 

ofPubsubItem (项目发布到节点)

列名类型长度描述serviceIDVARCHAR100编号托管服务节点(主键)nodeIDVARCHAR100编号的节点(主键)idVARCHAR100编号的出版项目(独特的每个节点)(主键)jidVARCHAR1024JID出版商creationDateVARCHAR15创建日期payloadTEXTn/aXML的有效载荷包括在出版项目

 

ofPubsubSubscription (订阅节点)

列名类型长度描述serviceIDVARCHAR100编号托管服务节点(主键)nodeIDVARCHAR100编号的节点(主键)idVARCHAR100编号认购(主键)jidVARCHAR1024地址接收通知ownerVARCHAR1024JID的子公司,拥有认购stateVARCHAR15国家认购(工作流程中的)deliverNUMBERn/a检举指出是否通知或未启用digestNUMBERn/a检举表明一个实体是否希望收到通知摘要digest_frequencyNUMBERn/a最低数目的毫秒之间发出任何两个通知消化expireVARCHAR15日期在租赁认购将结束或已经结束includeBodyNUMBERn/a检举表明一个实体是否希望收到邮件正文除了有效载荷格式showValuesVARCHAR30存在这些国家的实体希望收到通知subscriptionTypeVARCHAR10无论是用户订阅的项目或节点(收集节点只)subscriptionDepthNUMBERn/a收到通知的儿童一定深度(收集节点只)keywordVARCHAR200关键字活动必须符合

 

ofPubsubDefaultConf (默认配置节点)

列名类型长度描述serviceIDVARCHAR100编号托管服务节点(主键)leafNUMBERn/a检举指出是否配置属于叶或收集节点(主键)deliverPayloadsNUMBERn/a检举指出是否有效载荷中包含的通知maxPayloadSizeNUMBERn/a最大规模的有效载荷的字节persistItemsNUMBERn/a检举表明节点是否将持续出版项目maxItemsNUMBERn/a最大的项目数量将持续notifyConfigChangesNUMBERn/a检举指出是否发送通知时,该节点的配置发生了变化notifyDeleteNUMBERn/a检举指出是否发送通知时,该节点将被删除notifyRetractNUMBERn/a检举指出是否发送通知时,发布的项目将被删除presenceBasedNUMBERn/a检举指出是否发送通知只有用户才sendItemSubscribeNUMBERn/a检举指出是否向去年出版项目,以新用户publisherModelVARCHAR15Publisher中使用的模式的节点subscriptionEnabledNUMBERn/a检举指出是否允许订阅accessModelVARCHAR10访问模型所使用的节点languageVARCHAR255默认语言的节点replyPolicyVARCHAR15政策界定业主或出版商是否应得到答复项目associationPolicyVARCHAR15政策规定谁可以联系叶节点的集合maxLeafNodesNUMBERn/a马克斯一些叶节点,一个节点可能会收集

 

 

7WEB服务器

    Openfire采用内置的jetty作web服务器,在启动AdminConsolePlugin插件时调用startup()方法启动jetty服务器,9090为其明文端口,9091为其加密端口。

8页面处理

       Openfire没有采用现在很流行的技术架构(SSH),只使用JSP+JavaBean,但是它有自己的系统设计,就连日志都是自己做的,没有使用我们熟悉的log4j。

现有的Openfire管理控制台可采用插件方式进行扩展(详见插件开发说明部分介绍),页面采用Jsp方式实现,页面直接调用业务处理逻辑类(通常命名为XXManager)的实例方法,通常通过request对象封装的方式传递页面展现判定变量,常出现本页跳转。每个插件可定义自己的Servlet类和web.xml及web-custom.xml配置文件。

    采用装饰框架方式展现页面,decorator页面有两个,即src/web/decorators目录下的两个页面main.jsp和setup.jsp。采用自定义的admin标签实现,标签库admin.tld放置在src/web/WEB-INF目录下,标签解析类放置在org.jivesoftware.admin包下,有SidebarTag、SubnavTag、SubSidebarTag、TabsTag四个解析类。在调用loadPlugin()方法进行插件加载时,解析插件的plugin.xml配置文件,将获取的相关信息封装在AdminConsole类的generatedModel对象中,后期通过插件解析类提取该对象中的数据并配合sitemesh装饰器进行页面展现。详见“使用dom4j设计Openfire式导航菜单”部分相关介绍。

9插件开发

 

Openfire Plugins加载流程

 

 

官方插件开发说明

所有插件都存放在openfire根下的plugins目录下。当一个插件被以JAR或WAR文件发布时,他自动扩展为一个文件夹。插件目录结构如下所示:

Plugin Structure

myplugin/

 |- plugin.xml      <- 插件定义文件

 |- readme.html     <- 可选的插件自己述文件,它将被显示给最终用户。

 |- changelog.html  <-可选的插件版本日志文件,它将被展现给最终用户。

 |- logo_small.gif  <- 可选的与插件关联的小图标(16x16)文件(也能为png文件)

 |- logo_large.gif  <-可选的与插件关联的大图标(32x32)文件(也能为png文件)

 |- classes/        <- 你的插件需要的资源文件(如properties文件)

 |- database/       <- 可选的你的插件需要的数据库schema文件

 |- i18n/           <- 可选的i18n文件,它们为插件提供国际化支持

 |- lib/            <- 你的插件需要的库(JAR文件)

 |- web             <- 需要集成到管理控制台中的各类资源(如果有的话)

     |- WEB-INF/

         |- web.xml           <- 配置jsp调度的web.xml配置文件

         |- web-custom.xml    <- 可选的用户定义的web.xml文件,用于调度自定义servlets

     |- images/

 

 

若插件需要为Openfire的管理控制台添加内容,则web文件夹必须存在。具体内容详述如下。

 

Plugin.xml文件指定了主插件类,下面是一个例子。

 

Itvi plugin.xml

<?xml version="1.0" encoding="UTF-8"?>

<plugin>

    <!-- Main plugin class -->

    <class>plugin.Itvi</class>

 

    <!-- Plugin meta-data -->

    <name>TestPlugin</name>

    <description>This is an example plugin.</description>

    <author>Jive Software</author>

 

    <version>1.0</version>

    <date>07/01/2006</date>

    <url>http://www.igniterealtime.org/projects/openfire/plugins.jsp</url>

    <minServerVersion>3.0.0</minServerVersion>

    <licenseType>gpl</licenseType>

 

    <!-- Admin console entries -->

    <adminconsole>

        <!-- More on this below -->

        <tab id="mytab" name="Example" url="sample.html" description="Click to manage...">

            <sidebar id="mysidebar" name="My Plugin">

               <item id="my-plugin" name="My Plugin Admin"

                   url="sample.html"

                   description="Click to administer settings for my plugin" />

            </sidebar>

        </tab>

 

    </adminconsole>

</plugin>

 

 

各元数据域能在plugin.xml文件中进行设置:

·         name – 插件名.

·         description – 插件描述.

·         author – 插件作者.

·         version – 插件版本.

·         date – 插件版本生成日期。该日期必须为MM/dd/yyyy格式, 如07/01/2006.

·         url – 关于该插件的更多详细信息可以从该地址获取.

·         minServerVersion – 为运行该插件所需的最低的Openfire软件版本(Openfire 2.1.2及后续版本支持该选项).如果服务器版本低于需要的最低版本,插件将不会启动.

·         databaseKey – 如果插件需要它自己的数据库表,必须将databaseKey元素设置为一个schema key name(通常与插件同名). 然后需将所有需支持数据库类型的数据库schema 文件放到插件的database文件夹下. 例如,给一个关键字“foo”,那么schema文件需命名为"foo_mysql.sql", "foo_oracle.sql"等.我们建议你在命名你的表时加上前缀"of" (openfire),以避免与其他可能使用同一数据库的其他应用系统需要的表产生冲突.关于版本的描述信息需添加到ofVersion表中,以对应的key做标识,这样可以跟踪schema版本信息,如:

INSERT INTO ofVersion (name, version) VALUES (&apos;foo&apos;, 0);

·         databaseVersion – 数据库schema版本(如果定义了数据库schema)。有数据库schema的新插件的版本从0开始编号。如果以后的插件版本需要更新schema,这些更新能通过在database/upgrade目录下为各版本创建子目录的方式来定义。例如目录database/upgrade/1和database/upgrade/2将包括如 "foo_mysql.sql"和"foo_oracle.sql" 这样的包含各版本相应的数据库改变信息的脚本.这些脚本中均需要更新ofVersion表的信息,如:

UPDATE ofVersion set version=1 where name=&apos;foo&apos;;

·         parentPlugin – 父插件名 ("foo.jar"插件相应的为"foo").当一个插件有一个父插件,将不会创建一个新的class loader,相应地替换为使用父插件的class loader。这使得插件间能更紧密地联合工作。子插件不能脱离父插件独立工作。

·         licenseType – 指定许可类型信息。 有效值包括:

o    "commercial": 插件被发布为商业性插件。

o    "gpl": 插件被发布为遵循GNU Public License (GPL)协议。

o    "apache": 插件被发布为Apache license系列

o    "internal": 插件仅供内部使用,且不能被重新发布。

o    "other": 插件被发布为与其他目录下的版本限制不同。License许可信息需在插件自述文件中进行详细描述。

如果许可类型未设置,默认为other。

为了给最终用户提供插件的额外信息,可以为插件添加一些额外文件(全放置在插件的主目录下):

·         readme.html – 可选的插件自述文件,它的信息将展现给最终用户。

·         changelog.html --可选的插件版本日子文件,它将被展现给最终用户。

·         logo_small.png --可选的与插件关联的小图标(16x16)文件(也能为gif文件)。

·         logo_large.png --可选的与插件关联的大图标(32x32)文件(也能为gif文件)。

插件必须实现Plugin接口,且有一个默认构造函数。Plugin接口包含了初始化和销毁插件的方法。

Sample plugin implementation

package org.example;

 

import org.jivesoftware.openfire.container.Plugin;

import org.jivesoftware.openfire.container.PluginManager;

 

import java.io.File;

 

/**

 * A sample plugin for Openfire.

 */

public class ExamplePlugin implements Plugin {

 

    public void initializePlugin(PluginManager manager, File pluginDirectory) {

        // Your code goes here

 

    }

 

    public void destroyPlugin() {

        // Your code goes here

    }

}

 

0 0
原创粉丝点击