openfire的插件–內部插件開發
插件開發
基本
插件必須有一個實現Plugin。以創建HelloWorldPlugin
爲例子(下同)。在src/plugins/
下新建目錄helloworld
,如下
在src/plugins/helloworld/src/java
下添加插件代碼HelloWorldPlugin.java
public class HelloWorldPlugin implements Plugin {
private XMPPServer server;
public HelloWorldPlugin() {
}
@Override
public void initializePlugin(PluginManager managier, File pluginDirectory) {
server = XMPPServer.getInstance(); //當前實例
System.out.println("HelloWorldPlugin----start");
System.out.println(server.getServerInfo());
}
@Override
public void destroyPlugin() {
System.out.println("HelloWorldPlugin----destroy");
}
}
添加plugin.xml
,用於配置插件參數
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
<class>com.wangjiayong.HelloWorldPlugin</class>
<name>Helloworld</name>
<description>Adds clustering support</description>
<author>wangjiayong</author>
<version>0.1.0</version>
<date>02/11/2018</date>
<!-- openfire版本號 -->
<minServerVersion>4.2.0</minServerVersion>
<!--<licenseType>gpl</licenseType>-->
<!-- 管理控制檯的條目 -->
<adminconsole>
<!-- More on this below -->
</adminconsole>
</plugin>
需要在管理臺添加頁面,則在修改<adminconsole>
<adminconsole>
<tab id="tab-server">
<sidebar id="helloworldBar" name="helloworldBar" description="sidebar helloworld">
<item id="helloworld" name="helloworld"
url="index.jsp"
description="index helloworld"/>
</sidebar>
</tab>
</adminconsole>
並在src/plugins/helloworld/src/web
(和Web項目一樣,可以有WEB-INF等結構和Servlet)下,添加JSP文件,即tab.sidebar.item.url
<!DOCTYPE>
<html>
<body>
<h3>Test HelloWorld</h3>
</body>
</html>
最後將helloworld
打包。修改build/build.properties
,添加plugin=helloworld
(插件目錄名),然後執行Ant Build->plugins,openfire會自動發佈,將插件添加到管理臺上。(todo:二級導航沒出來,啓動順序未知)
跳轉到helloworld的主頁
攔截器
流過插件的數據爲Packet,可以是Message,IQ、Presence,使用PacketInterceptor攔截,可以和Plugin一起實現。
注意:一旦interceptPacket
函數內部拋出PacketRejectedException
異常,那麼流入interceptPacket
中的packet包將被丟棄,不再往下走。當這個異常PacketRejectedException
對象中的message不爲空的時候,會給發送者返回一條body爲fuck is error的消息。
在src/plugins/helloworld/src/java
添加ContentFilter
public class ContentFilter implements PacketInterceptor {
// 攔截器管理器,所有的攔截器都在這裏註冊
private InterceptorManager interceptorManager;
public void initializePlugin(PluginManager pManager, File pluginDirectory) {
interceptorManager = InterceptorManager.getInstance();
// 將攔截器註冊進來,這樣有Packet來的時候,就會(鏈式)調用interceptPacket
interceptorManager.addInterceptor(this);
}
public void destroyPlugin() {
// 插件卸載時,記得將攔截器從系統中移出。
interceptorManager.removeInterceptor(this);
}
// 實際處理數據,過濾文本信息爲例
public void interceptPacket(Packet packet, Session session, boolean read,
boolean processed) throws PacketRejectedException {
// read爲true表示本條消息剛進入openfire。processed爲false,表示本條消息沒有被openfire處理過。
if (read && processed == false) {
// packet可能是IQ、Presence、Message,這裏當packet是message的時候,進行處理。
if (packet instanceof Message) {
Message msg = (Message)packet;
//Message.Type.chat單聊,Message.Type.groupchat羣聊
//取出正文
String body = msg.getBody();
// 如果內容中包含fuck,則拒絕處理消息
if(body != null && body.contains("fuck")){
//拋出異常,返回給用戶信息RejectionMessage
PacketRejectedException rejectedException = new PacketRejectedException();
rejectedException.setRejectionMessage("fuck is error");
throw rejectedException;
}
}
}
}
}
操作數據庫
在自定義插件根目錄下,即/添加sql腳本,openfire會根據數據庫類型自動建表
在plugin.xml
中添加數據庫表名
<databaseKey>helloworld</databaseKey>
<databaseVersion>0</databaseVersion>
相關邏輯
import org.jivesoftware.database.DbConnectionManager;
import org.jivesoftware.database.JiveID;
import org.jivesoftware.database.SequenceManager;
import org.jivesoftware.openfire.XMPPServer;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
@JiveID(55)
public class HelloWorldPlugin implements Plugin {
private static final String INSERT_HELLOWORLD = "INSERT INTO ofHelloworld(hID, msg) VALUES (?,?)";
private void insertIntoDb() throws SQLException {
long hID = SequenceManager.nextID(this);
Connection con = null;
boolean abortTransaction = false;
try {
con = DbConnectionManager.getTransactionConnection();
PreparedStatement pstmt = con.prepareStatement(INSERT_HELLOWORLD);
pstmt.setLong(1, hID);
pstmt.setString(2, "content"+UUID.randomUUID().toString());
pstmt.executeUpdate();
pstmt.close();
System.out.println("hello success in db");
}
catch (SQLException sqle) {
abortTransaction = true;
throw sqle;
}
finally {
DbConnectionManager.closeTransactionConnection(con, abortTransaction);
}
}
}
SQL腳本如下,INSERT INTO ofVersion (name, version)
用於判斷是否執行後續SQL語句。
INSERT INTO ofVersion (name, version) VALUES ('helloworld', 0);
CREATE TABLE ofHelloworld world (
hID BIGINT NOT NULL,
msg VARCHAR(50) NOT NULL,
CONSTRAINT ofHelloworld_pk PRIMARY KEY (hID)
);
//TODO,沒成功創建表,操作openfire本身的表是成功的,待解決
java.sql.SQLSyntaxErrorException: user lacks privilege or object not found: OFHELLOWORLD in statement [insert into OFHELLOWORLD(hID, msg) values (?,?)]
查看(內置)數據庫,一般在target
目錄,配置如下圖
#具體的項目target路徑
cd /d D:\wjywork\wj\openfire\target\openfire\lib
java -cp hsqldb.jar org.hsqldb.util.DatabaseManagerSwing
此時在openfire\target\openfire\embedded-db
中生成了openfire.script
,裏面有相關數據的SQL,可以用於數據庫遷移。注意打開hsqldb.jar
後,數據庫已經處於鎖定狀態,openfire就不能使用了。
用戶
通過攔截器,可以獲取每個Pacekt的信息,比如根據JID獲取具體用戶信息。
import org.jivesoftware.openfire.user.UserManager;
import org.jivesoftware.openfire.user.User;
public void interceptPacket(Packet packet, Session session, boolean read,
boolean processed) throws PacketRejectedException{
JID fromJID = packet.getFrom(); //發送者
JID toJID = packet.getTo(); //接收者
final UserManager userManager = UserManager.getInstance();
try {
User user = userManager.getUser(toJID.getNode());
user.getName();
}
catch (UserNotFoundException e) {
}
}