一. 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的前輩。
二. 命名規則
Openfire中常見的類名字尾命名包括Starter、Plugin、Listener、Dispatcher、Handler、Manager、Provider,通常情況下,這些命名類包括如下意義:
XXStarter
系統啟動類,如org.jivesoftware.openfire.starter.ServerStarter,調用其start()方法可啟動系統應用。
XXListener
業務的最終處理類。
XXDispatcher
排程類,其中有很多關鍵方法,如addListener(),以組合的方式,為類内定義的靜态Set<XXListener>執行個體添加XXListener對象。以便調用dispatchEvent(Stringproperty, EventType eventType, Map<String, Object> params)方法周遊處理Set集中的XXListener對象(通過調用XXListener對象的各實際方法完成實際業務)。
XXPlugin
實作Plugin接口的插件類,需實作initializePlugin(PluginManagermanager, File pluginDirectory)方法和destroyPlugin()方法。在其初始化方法中調用Dispatcher實作類的addListener()方法如PropertyEventDispatcher.addListener(this)。
XXProvider
實作面向接口程式設計方式的接口類,通過反射機制建立具體實作類的對象,反射類名配置在ofproperty表對應的記錄propvalue屬性中。若沒有相關配置,則調用預設實作類,預設實作類類名命名規則為DefaultXXProvider。
XXHandler
實際處理類,以ConnectionHandler為例,在org.jivesoftware.openfire.spi.ConnectionManagerImpl類的startClientSSLListeners(StringlocalIPAddress)方法中,有這樣一段代碼:
sslSocketAcceptor.bind(newInetSocketAddress(bindInterface, port), newClientConnectionHandler(serverName));其中bind方法的第二個參數是新建立的一個ClientConnectionHandler的執行個體,而它就是ConnectionHandler的一個子類。
三. 系統配置項
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,分别代表配置項名和配置項值。
四. 系統啟動流程
系統啟動時調用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)方法實作)。
五. 網絡處理
消息監聽服務
SSL等監聽服務的排程在ConnectionManagerImpl類中實作。ConnectionManagerImpl.createClientSSLListeners()方法啟動SSL監聽
消息封裝
資訊處理采用XML節的方式傳遞資訊,消息封裝通常采用IQ、Message、Presence。
Openfire消息包接受處理流程
六. 資料庫處理
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
七. WEB伺服器
Openfire采用内置的jetty作web伺服器,在啟動AdminConsolePlugin插件時調用startup()方法啟動jetty伺服器,9090為其明文端口,9091為其加密端口。
頁面處理
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式導航菜單”部分相關介紹。