- 第一步 – 預處理 – XMPPPreprocessorIfc:這是預處理器插件需要實現的接口
- 第二步 – 處理 – XMPPProcessorIfc:這是處理器插件需要實現的接口
- 第三步 – 投遞 – XMPPPostProcessorIfc:這是投遞處理器插件需要實現的接口
- 第四步 – 過濾 – XMPPPacketFilterIfc:這是結果過濾器插件需要實現的接口
public class SpamFilterPlugin extends XMPPProcessor implements XMPPProcessorIfc { @Override
public void process(Packet packet, XMPPResourceConnection session, NonAuthUserRepository repo, Queue<Packet> results, Map<String, Object> settings) throws XMPPException { // code here... }
}要做的第一件事情就是確定插件ID。它是唯一的,需要放到配置文件裏面,告訴服務器在啓動時加載並使用相對應的插件。
如果這個插件需要只對特定命名空間下特定名稱的元素“感興趣”,那麼我們需要定義XMLNS元素來定義命名空間。
|
/** * @param settings Map<String, Object> 爲PLUGIN制定配置信息,一般情況下不需要使用,然而如果需要訪問額外的數據庫則可以通過配置文件將數據庫連接字符串傳給plugin //code here ... } }catch (NotAuthorizedException ex) { log.log(Level.WARNING, "NotAuthorizedException for packet: {0}", packet); } |
--sm-plugins=spam-filter-xep-0076
備註說明 #如果需要添加(+,默認爲+,可忽略不寫)或刪除(-)插件規則是使用加減號前綴即可
#如果給這個插件還定義了參數,那麼我們可以參考這樣的規則
eg. sess-man/plugins-conf/spam-filter-xep-0076/component-jid=[email protected] |
4. 在客戶端發請求進行調用
<message to="[email protected]" id="OHPTO-19" type="chat" xmlns="jabber:client" from="[email protected]/Spark"><body>sdf(測試內容發送)</body><thread>qcNhnm</thread><x xmlns="jabber:x:event"><offline/><composing/></x></message>
可以看到報文中的命名空間爲:xmlns="jabber:client",我們定義的插件對這個消息就會"感興趣",這種消息就會被轉發到我們定義的插件進行處理。
eg.
<message to="[email protected]" id="OHPTO-19" type="chat" xmlns="jabber:client" from="[email protected]/Spark">
<body>sdf(測試內容發送)packet3</body><thread>qcNhnm</thread> <x xmlns="jabber:x:event"><offline/><composing/></x> </message> |
public void process(finalPacket packet,
final XMPPResourceConnection session,
final NonAuthUserRepository repo,
final Queue<Packet> results,
final Map<String, Object> settings)
throwsXMPPException {
// 出於性能的考慮,最好在打印日誌之前現檢查一下日誌級別
if(log.isLoggable(Level.FINEST)) {
log.finest("Processing packet: "+ packet.toString());
}
// 如果用戶不在線,你也許想跳過後面的處理環節
if(session ==null) {
return;
}// end of if (session == null)
// 當插件在第一次處理這個用戶的會話信息的時候,還有另外一種方法可以執行必要的操作
if(session.getSessionData(ID) ==null) {
session.putSessionData(ID, ID);
// 你可以把你的代碼放到這裏
.....
// 如果你不希望終止操作,那麼就把return語句去掉
return;
}
// 如果用戶的會話沒有授權,那麼每一次調用session.getUserId()方法都會拋出異常
try{
// 在比較JID之前一定記得要去掉resource部分
// JID的組成:jid = [ node "@" ] domain [ "/" resource ]
// 比如:[email protected]/home
String id = JIDUtils.getNodeID(packet.getElemTo());
// 檢查一下這個packet是否是發給會話的擁有者
if(session.getUserId().equals(id)) {
// 如果是,那麼這個消息的確是要發送給這個客戶端的
Element elem = packet.getElement().clone();
Packet result =newPacket(elem);
// 這裏就是我們爲最終收到消息的用戶設置客戶端組件地址的地方了
// 在大多數情況,這可能是一個能夠保持於客戶端連接的c2s或Bosh組件
result.setTo(session.getConnectionId(packet.getElemTo()));
// 在大多數情況,這一步可以跳過,但是當packet的投遞過程出現了什麼問題,這麼做可以爲調用者返回一個錯誤
result.setFrom(packet.getTo());
// 最後不要忘記把結果packet放到結果隊列裏面去,否則結果會丟失
results.offer(result);
}// end of else
// 在比較JID之前一定記得要去掉resource部分
id = JIDUtils.getNodeID(packet.getElemFrom());
// 檢查一下這個packet是否由會話的擁有者發出
if(session.getUserId().equals(id)) {
// 這是一個由客戶端發出的packet,最簡單的處理就是把packet轉發到packet的目的地地址:
// 簡單的對XML元素進行克隆,然後……
Element result = packet.getElement().clone();
// 把他放到傳出packet隊列裏面就行了
results.offer(newPacket(result));
return;
}
// 程序真的會運行到這裏嗎?
// 是的,一些packet即沒有from也沒有to地址。最容易理解的一個例子是向服務器發送的獲取某些數據的IQ請求。這類packet沒有任何地址,並且需要對它做很多複雜的處理
// 下面的代碼展示瞭如何確定這個seesion就是請求發起者的session
id = packet.getFrom();
// 下面的處理和檢查getElementFrom差不多
if(session.getConnectionId().equals(id)) {
// 這裏需要針對IQ packet做一些特別處理,但是我們需要處理的是message,所以這裏只需要對它進行轉發
Element result = packet.getElement().clone();
// 如果程序運行到這裏說明packet的from地址是沒有的,現在對from屬性就行設置
result.setAttribute("from", session.getJID());
// 最後把傳出packet放到結果隊列裏面就ok樂
results.offer(newPacket(result));
}
}catch(NotAuthorizedException e) {
log.warning("NotAuthorizedException for packet: " +
packet.getStringData());
results.offer(Authorization.NOT_AUTHORIZED.getResponseMessage(packet,
"You must authorize session first.",true));
}// end of try-catch
}
|