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类中的下面两个方法会执行添加的监听器
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()在进行消息路由失败的情况下开始的:
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中查询这个接口
相关文章推荐
- openfire服务端消息回执插件(接收方离线时的情况),判断用户的在线状态
- OpenFire源码学习之二十四:消息回执与离线消息(上)
- OpenFire源码学习之二十四:消息回执与离线消息(上)
- 源码详解openfire保存消息记录_修改服务端方式
- OpenFire源码学习之二十五:消息回执与离线消息(下)
- openfire服务端消息回执插件(接收方离线时的情况),判断用户的在线状态
- OpenFire源码学习之二十五:消息回执与离线消息(下)
- xmpp和OpenFire实例,实现即时聊天室,支持离线消息
- openfire离线消息乱码
- openfire服务端消息回执插件(接收方离线时的情况),判断用户的在线状态
- openfire插件最佳实践(四)离线消息推送ios服务器
- tigase增加离线消息和保存历史记录
- OpenFire源码学习之二十四:消息回执与离线消息(上)
- openfire离线消息乱码(XMPP)
- 解决Openfire在使用mysql时的离线消息、昵称、备注等乱码问题
- xmpp和OpenFire示例,即时聊天室,支持离线消息
- OpenFire源码学习之二十四:消息回执与离线消息(上)
- #xmpp笔记# Android获取openfire离线消息
- OpenFire源码学习之二十五:消息回执与离线消息(下)
- 源码详解openfire保存消息记录_修改服务端方式