Tigase开发笔记4:如何自定义插件 Plugin

其他博客比较好的介绍推荐:http://my.oschina.net/greki/blog/209726

1. 定义一个插件

四种处理器插件接口:

  1. 第一步 – 预处理 – XMPPPreprocessorIfc:这是预处理器插件需要实现的接口
  2. 第二步 –  处理 –    XMPPProcessorIfc:这是处理器插件需要实现的接口
  3. 第三步 –  投递 –    XMPPPostProcessorIfc:这是投递处理器插件需要实现的接口
  4. 第四步 –  过滤 –    XMPPPacketFilterIfc:这是结果过滤器插件需要实现的接口

如果要开发一个处理器插件,那么就需要实现XMPPProcessorIfc接口;如果是预处理插件,就需要实现XMPPPreprocessorIfc接口;

当然你也可以实现多个接口,这个取决于你的需求和情况,你也可以继承处理器Helper抽象类(XMPPProcessor.java抽象类)作为基类来实现所有的插件。

public class SpamFilterPlugin extends XMPPProcessor implements XMPPProcessorIfc {

/** Field : Plugin ID Setting ,this‘ very important 定义插件ID */private static final String ID        = "spam-filter-xep-0076";/** Field : Plugin xmlns Setting ,this‘ very important 定义命名空间 */private static final String    XMLNS    = "jabber:client";
@Override
  public void process(Packet packet, XMPPResourceConnection session, NonAuthUserRepository repo, Queue<Packet> results, Map<String, Object> settings)
      throws XMPPException {
       // code here...
   }

}

要做的第一件事情就是确定插件ID。它是唯一的,需要放到配置文件里面,告诉服务器在启动时加载并使用相对应的插件。

如果这个插件需要只对特定命名空间下特定名称的元素“感兴趣”,那么我们需要定义XMLNS元素来定义命名空间。

下面用一张图总结一下怎样定义一个插件

2. 重要的处理方法process介绍

/** * 处理消息* @param packet 在PROCESS处理过程中无法修改它 * @param session XMPPResourceConnection用于保存所有用户的数据,它提供权限访问用户的仓库数据,在没有在线用户SESSION的情况下该参数可以为null * @param repo NonAuthUserRepository该参数往往在参数session为NULL的时候被使用,它用于为不在线的用户保存私有或公开的数据信息。 * @param results Queue<Packet>这个为输入数据包的处理结果产生的数据包集合,它总被要求一定要存放一个输入数据包PACKET的备份到里面,其实包含了所有需要处理的PACKET,<strong>包括process生成的结果packet</strong>
 * @param settings Map<String, Object>  为PLUGIN制定配置信息,一般情况下不需要使用,然而如果需要访问额外的数据库则可以通过配置文件将数据库连接字符串传给plugin * * @throws XMPPException */@Overridepublic void process(Packet packet, XMPPResourceConnection session, NonAuthUserRepository repo, Queue<Packet> results, Map<String, Object> settings)throws XMPPException {if (session == null) {return;   }try {
      //code here ...if (Message.ELEM_NAME == packet.getElemName()) {
      }
  }catch (NotAuthorizedException ex) {
log.log(Level.WARNING, "NotAuthorizedException for packet: {0}", packet);   results.offer(Authorization.NOT_AUTHORIZED.getResponseMessage(packet,"You must authorize session first.", true));  }
}

3. 在init.properties文件中配置插件


--sm-plugins=spam-filter-xep-0076


备注说明
#如果需要添加(+,默认为+,可忽略不写)或删除(-)插件规则是使用加减号前缀即可
--sm-plugins=+spam-filter-xep-0076,-jabber:iq:register
#如果给这个插件还定义了参数,那么我们可以参考这样的规则
sess-man/plugins-conf/插件ID/参数key = 参数value

eg.
sess-man/plugins-conf/spam-filter-xep-0076/component-jid=[email protected]sess-man/plugins-conf/spam-filter-xep-0076/default-store-method=message


4. 在客户端发请求进行调用

我使用的是Openfire的Spark客户端进行调试(Spark登陆界面->高级->启用调试模式->登录)

发送报文


<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>

5. 常见的一些proccess中的代码处理

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

}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-19 18:01:24

Tigase开发笔记4:如何自定义插件 Plugin的相关文章

Tigase开发笔记1:深入认识XMPP协议

要学习基于XMPP协议的IM开发,首先要熟悉XMPP协议本身. XMPP协议的组成 主要的XMPP 协议范本及当今应用很广的XMPP 扩展: RFC 3920 XMPP:核心.定义了XMPP 协议框架下应用的网络架构,引入了XML Stream(XML 流)与XML Stanza(XML 节),并规定XMPP 协议在通信过程中使用的XML 标签.使用XML 标签从根本上说是协议开放性与扩展性的需要.此外,在通信的安全方面,把TLS 安全传输机制与SASL 认证机制引入到内核,与XMPP 进行无缝

iOS开发笔记17:自定义相机拍照

之前用AVFoundation自定义相机做了拍照与视频相关的东西,为什么要自定义呢?主要是提供更个性化的交互设计,符合app主题,对于视频来说,也便于提供更多丰富有趣的功能.前段时间整理了下拍照部分的功能,主要分为以下五个部分 1.初始化,建立会话,获取摄像头 使用AVCaptureSessionPresetPhoto模式,输出的图片分辨率与系统相机输出的分辨率保持一致 添加后置摄像头与图片输出(默认采用后置摄像头拍摄) 2.嵌入实时预览层 获取实时预览画面,添加手势,初始化时默认在画面中心点对

Vue-cli开发笔记三----------引入外部插件

(一)绝对路径直接引入: (1)主入口页面index.html中头部script标签引入: 1 <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=n0S34gQ0FW73Vj7X13A4y75q"></script> (2)build/webpack.base.conf.js 中配置: externals 1 let webpackCon

Tigase开发笔记6:packet流转机制 -&gt; 一条消息(packet)的请求和响应过程解析

初看Tigase的packet内部流转机制一开始不是太明白.里面用到了较多的线程,代码不太看得懂.慢慢的通过一条消息的请求和响应的代码跟踪分析,搞清楚了消息流转的过程. 前言 本文使用Tigase Server version:7.0.2 进行的代码跟踪和分析. 使用工具:IntelliJ IDEA14.1.4 Tigase通过tigase.io包当中的代码读取网络中的字节数组,然后通过tigase.net包当中的类把字节数组转换为字符,最后通过tigase.xml包当中的XML解析器把这些字符

Android Cordova 插件开发之编写自定义插件

前言 本文适合Android+web的复合型人才,因为cordova本身就是混合开发,所以在Android开发的基础上,还要懂web相关技术(HTML+CSS+JS),但是也有例外,比如我,只需负责Android方面,web方面的交由其他web组人员开发.虽然,web略懂一点,但我主要还是搞Android开发的. 编写自定义插件类 本节的内容是,自定义一个dialog插件,供web调用,显示系统弹窗. 新建一个包名,我这里使用org.apache.cordova.dialog,然后创建个类Cus

cordova3.X 运用grunt生成plugin自定义插件骨架

Cordova提供了一组设备相关的API,通过这组API,移动应用能够以JavaScript访问原生的设备功能,如摄像头.麦克风等.Cordova还提供了一组统一的JavaScript类库,以及为这些类库所用的设备相关的原生后台代码. 一.安装cordova npm install -g cordova 二.创建项目 cordova create hello com.blue.sky.hybrid.app.hello HelloWorld 三.添加平台支持 cd hello cordova pl

android开发笔记之自定义开关按钮

今天来讲讲自定义单个控件,就拿开关按钮来讲讲,相信大家见了非常多这样的了,先看看效果: 我们可以看到一个很常见的开关按钮,那就来分析分析. 首先: 这是由两张图片构成: ①一张为有开和关的背景图片 ②一张为控制开和关的滑动按钮 第一步: 写个类继承View,并重写几个方法: 第一个为构造函数,重写一个参数的函数和两个参数的函数就够了,因为两个参数的函数能够使用自定义属性 第二个为控制控件的大小–>protected void onMeasure(int widthMeasureSpec, int

安卓开发笔记——高仿新浪微博文字处理(实现关键字高亮,自定义表情替换并加入点击事件实现)

先让大家看下效果图,这个是我自己在闲暇时间仿写的新浪微博客户端: 今天来讲讲如何实现上图的效果,这里需要用到SpannableString这个工具类,如果你对这个类并不熟悉,可以先看下我之前写的2篇文章: <安卓开发笔记——个性化TextView(新浪微博)>:http://www.cnblogs.com/lichenwei/p/4411607.html <安卓开发笔记——丰富多彩的TextView>:http://www.cnblogs.com/lichenwei/p/46120

Android开发笔记(一百一十八)自定义悬浮窗

WindowManager 在前面<Android开发笔记(六十六)自定义对话框>中,我们提到每个页面都是一个Window窗口,许多的Window对象需要一个管家来打理,这个管家我们称之为WindowManager窗口管理.在手机屏幕上新增或删除页面窗口,都可以归结为WindowManager的操作,下面是该管理类的常用方法说明: getDefaultDisplay : 获取默认的显示屏信息.通常用该方法获取屏幕分辨率,详情参见<Android开发笔记(三)屏幕分辨率>. addV