openfire 保存离线消息

来源:互联网 发布:五轴加工中心编程 编辑:程序博客网 时间:2024/05/18 20:32

文章参考 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 storedif (!listeners.isEmpty()) {for (OfflineMessageListener listener : listeners) {listener.messageStored(message);}}}private void bounce(Message message) {// Do nothing if the sender was the server itselfif (message.getFrom() == null) {return;}try {// Generate a rejection response to the senderMessage 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 responserouter.route(errorResponse);// Inform listeners that an offline message was bouncedif (!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 serverrouted = routeToComponent(jid, packet, routed);}else {// Packet sent to remote serverrouted = 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 JIDif (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 (UserNotFoundException 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中查询这个接口

 

0 0
原创粉丝点击