您的位置:首页 > 运维架构

openfire 保存离线消息

2016-09-07 17:22 387 查看
文章参考 http://www.cnblogs.com/yjl49/archive/2011/07/22/2371969.html
 

OfflineMessagetrategy —— 离线消息的处理策略类。

 

1.静态成员变量type 用来设置消息的处理类型,主要包括:

          打回        

          丢弃

          存储,在超限情况下打回

          存储,在超限情况下丢弃

 

2.静态成员变量quota 标识最大所能存储的message总和大小默认为100k。

 

3.支持OfflineMessageListener事件监听器,只要实现此接口并加入到监听器列表,则在消息被打回或存储时可扑捉到相应消息。        

备注:在OfflineMessagetrategy类中的下面两个方法会执行添加的监听器

private static List<OfflineMessageListener> listeners = new CopyOnWriteArrayList<OfflineMessageListener>();
/**
* Registers a listener to receive events.
*
* @param listener the listener.
*/
public static void addListener(OfflineMessageListener listener) {
if (listener == null) {
throw new NullPointerException();
}
listeners.add(listener);
}

/**
* Unregisters a listener to receive events.
*
* @param listener the listener.
*/
public static void removeListener(OfflineMessageListener listener) {
listeners.remove(listener);
}
private void store(Message message) {
messageStore.addMessage(message);
// Inform listeners that an offline message was stored
if (!listeners.isEmpty()) {
for (OfflineMessageListener listener : listeners) {
listener.messageStored(message);
}
}
}

private void bounce(Message message) {
// Do nothing if the sender was the server itself
if (message.getFrom() == null) {
return;
}
try {
// Generate a rejection response to the sender
Message errorResponse = message.createCopy();
errorResponse.setError(new PacketError(PacketError.Condition.item_not_found,
PacketError.Type.continue_processing));
errorResponse.setFrom(message.getTo());
errorResponse.setTo(message.getFrom());
// Send the response
router.route(errorResponse);
// Inform listeners that an offline message was bounced
if (!listeners.isEmpty()) {
for (OfflineMessageListener listener : listeners) {
listener.messageBounced(message);
}
}
}
catch (Exception e) {
Log.error(e.getMessage(), e);
}
}

 

4.所有离线消息都存储在表ofoffline中。

 

 

OfflineMessageStore:

用来具体处理离线消息的类。

 

1.用addMessage(Message message)来存储一条消息。

 

2.用getMessages(String username,boolean delete)来提供指定用户的所有离线消息。delete参数则是指定提取后是否要从数据库中删除。

 

3.用deleteMessages(String username)来删除某个用户所有的离线消息。

 

4.此类实现了UserEventListener接口,当用户被删除时掉用deleteMessage()来删除此用户所有离线消息。

 

离线消息的存储时机:

1.routingFailed()在进行消息路由失败的情况下。比如目的用户不在线。

 

2.由ConnectonManager转发过来的消息找不到路由或无法处理。

 

离线消息的提取时机:

1.用户状态变为可用,session被初始化时。比如用户上线。

 

2.用户发送了特定的IQ消息,要求递送自己发送的离线消息。

 

3.用户的session权限级别发生了变化。

  

我查看代码的入口是从routingFailed()在进行消息路由失败的情况下开始的

 

RoutingTableImpl类中的
/*
* (non-Javadoc)
* @see org.jivesoftware.openfire.RoutingTable#routePacket(org.xmpp.packet.JID, org.xmpp.packet.Packet, boolean)
*
* @param jid the recipient of the packet to route.
* @param packet the packet to route.
* @param fromServer true if the packet was created by the server. This packets should
*        always be delivered
* @throws PacketException thrown if the packet is malformed (results in the sender's
*      session being shutdown).
*/
public void routePacket(JID jid, Packet packet, boolean fromServer) throws PacketException {
boolean routed = false;
if (serverName.equals(jid.getDomain())) {
// Packet sent to our domain.
routed = routeToLocalDomain(jid, packet, fromServer);
}
else if (jid.getDomain().contains(serverName)) {
// Packet sent to component hosted in this server
routed = routeToComponent(jid, packet, routed);
}
else {
// Packet sent to remote server
routed = routeToRemoteDomain(jid, packet, routed);
}

if (!routed) {
if (Log.isDebugEnabled()) {
Log.debug("RoutingTableImpl: Failed to route packet to JID: {} packet: {}", jid, packet.toXML());
}
if (packet instanceof IQ) {
iqRouter.routingFailed(jid, packet);
}
else if (packet instanceof Message) {
//查看routingFailedf()方法里面的内容
messageRouter.routingFailed(jid, packet);
}
else if (packet instanceof Presence) {
presenceRouter.routingFailed(jid, packet);
}
}
}

/**
* Notification message indicating that a packet has failed to be routed to the recipient.
*
* @param recipient address of the entity that failed to receive the packet.
* @param packet Message packet that failed to be sent to the recipient.
*/
public void routingFailed(JID recipient, Packet packet) {
// If message was sent to an unavailable full JID of a user then retry using the bare JID
if (serverName.equals(recipient.getDomain()) && recipient.getResource() != null &&
userManager.isRegisteredUser(recipient.getNode())) {
routingTable.routePacket(recipient.asBareJID(), packet, false);
} else {
// Just store the message offline
//将消息保存到数据库中ofoffline表中
messageStrategy.storeOffline((Message) packet);
}
}
备注:userManager.isRegisteredUser(recipient.getNode())这个类会判断用户是否是注册用户,

/**
* Returns true if the specified local username belongs to a registered local user.
*
* @param username to username of the user to check it it's a registered user.
* @return true if the specified JID belongs to a local registered user.
*/
public boolean isRegisteredUser(String username) {
if (username == null || "".equals(username)) {
return false;
}
try {
getUser(username);
return true;
}
catch (UserNotFoun
4000
dException e) {
return false;
}
}
备注:getUser(username)就是从缓存或者数据库中查询用户

/**
* Returns the User specified by username.
*
* @param username the username of the user.
* @return the User that matches <tt>username</tt>.
* @throws UserNotFoundException if the user does not exist.
*/
public User getUser(String username) throws UserNotFoundException {
if (username == null) {
throw new UserNotFoundException("Username cannot be null");
}
// Make sure that the username is valid.
username = username.trim().toLowerCase();
//判断用户是否在缓存中
User user = userCache.get(username);
if (user == null) {
synchronized (username.intern()) {
user = userCache.get(username);
if (user == null) {
//用户不在缓存中则从数据库中查询这个用户是否在用户表中,如果存在则放入缓存中
user = provider.loadUser(username);
userCache.put(username, user);
}
}
}
return user;
}
备注:provider是UserProvider接口的实例,这个接口就是访问用户表的接口,具体的实现类是根据具体的配置实现的,可以在ofproperty中查询这个接口

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: