⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 presenceupdatehandler.java

📁 openfire 服务器源码下载
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
                    + localServer.getServerInfo().getXMPPDomain()
                    + " by unknown user: " + update.getFrom());
        }
    }

    /**
     * Notification method sent to this handler when a user has sent a directed
     * presence to an entity. If the sender of the presence is local (to this server)
     * and the target entity does not belong to the user's roster then update the
     * registry of sent directed presences by the user.
     *
     * @param update  the directed Presence sent by the user to an entity.
     * @param handlerJID the JID of the handler that will receive/handle/process the sent packet.
     * @param jid     the receipient specified in the packet to handle.
     */
    public void directedPresenceSent(Presence update, JID handlerJID, String jid) {
        if (update.getFrom() == null) {
            return;
        }
        if (localServer.isLocal(update.getFrom())) {
            boolean keepTrack = false;
            String name = update.getFrom().getNode();
            if (name != null && !"".equals(name)) {
                // Keep track of all directed presences if roster service is disabled
                if (!RosterManager.isRosterServiceEnabled()) {
                    keepTrack = true;
                }
                else {
                    try {
                        Roster roster = rosterManager.getRoster(name);
                        // If the directed presence was sent to an entity that is not in the user's
                        // roster, keep a registry of this so that when the user goes offline we
                        // will be able to send the unavailable presence to the entity
                        RosterItem rosterItem = null;
                        try {
                            rosterItem = roster.getRosterItem(update.getTo());
                        }
                        catch (UserNotFoundException e) {
                            // Ignore
                        }
                        if (rosterItem == null ||
                                RosterItem.SUB_NONE == rosterItem.getSubStatus() ||
                                RosterItem.SUB_TO == rosterItem.getSubStatus()) {
                            keepTrack = true;
                        }
                    }
                    catch (UserNotFoundException e) {
                        Log.warn("Presence being sent from unknown user " + name, e);
                    }
                    catch (PacketException e) {
                        Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
                    }
                }
            }
            else if (update.getFrom().getResource() != null){
                // Keep always track of anonymous users directed presences
                keepTrack = true;
            }
            if (keepTrack) {
                String sender = update.getFrom().toString();
                Lock lock = CacheFactory.getLock(sender, directedPresencesCache);
                try {
                    lock.lock();
                    Collection<DirectedPresence> directedPresences = directedPresencesCache.get(sender);
                    if (Presence.Type.unavailable.equals(update.getType())) {
                        if (directedPresences != null) {
                            // It's a directed unavailable presence
                            if (routingTable.hasClientRoute(handlerJID)) {
                                // Client sessions will receive only presences to the same JID (the
                                // address of the session) so remove the handler from the map
                                for (DirectedPresence directedPresence : directedPresences) {
                                    if (directedPresence.getHandler().equals(handlerJID)) {
                                        directedPresences.remove(directedPresence);
                                        break;
                                    }
                                }
                            }
                            else {
                                // A service may receive presences for many JIDs so in this case we
                                // just need to remove the jid that has received a directed
                                // unavailable presence
                                for (DirectedPresence directedPresence : directedPresences) {
                                    if (directedPresence.getHandler().equals(handlerJID)) {
                                        directedPresence.removeReceiver(jid);
                                        if (directedPresence.isEmpty()) {
                                            directedPresences.remove(directedPresence);
                                        }
                                        break;
                                    }
                                }
                            }
                            if (directedPresences.isEmpty()) {
                                // Remove the user from the registry since the list of directed
                                // presences is empty
                                directedPresencesCache.remove(sender);
                                localDirectedPresences.remove(sender);
                            }
                            else {
                                directedPresencesCache.put(sender, directedPresences);
                                localDirectedPresences.put(sender, directedPresences);
                            }
                        }
                    }
                    else {
                        if (directedPresences == null) {
                            // We are using a set to avoid duplicate jids in case the user
                            // sends several directed presences to the same handler. The Map also
                            // ensures that if the user sends several presences to the same handler
                            // we will have only one entry in the Map
                            directedPresences = new ConcurrentLinkedQueue<DirectedPresence>();
                        }
                        // Add the handler to the list of handler that processed the directed
                        // presence sent by the user. This handler will be used to send
                        // the unavailable presence when the user goes offline
                        DirectedPresence affectedDirectedPresence = null;
                        for (DirectedPresence directedPresence : directedPresences) {
                            if (directedPresence.getHandler().equals(handlerJID)) {
                                affectedDirectedPresence = directedPresence;
                                break;
                            }
                        }

                        if (affectedDirectedPresence == null) {
                            affectedDirectedPresence = new DirectedPresence(handlerJID);
                            directedPresences.add(affectedDirectedPresence);
                        }
                        affectedDirectedPresence.addReceiver(jid);

                        directedPresencesCache.put(sender, directedPresences);
                        localDirectedPresences.put(sender, directedPresences);
                    }
                } finally {
                    lock.unlock();
                }
            }
        }
    }

    /**
     * Sends an unavailable presence to the entities that received a directed (available) presence
     * by the user that is now going offline.
     *
     * @param update the unavailable presence sent by the user.
     */
    private void broadcastUnavailableForDirectedPresences(Presence update) {
        JID from = update.getFrom();
        if (from == null) {
            return;
        }
        if (localServer.isLocal(from)) {
            // Remove the registry of directed presences of this user
        	Collection<DirectedPresence> directedPresences = null;
        	
        	Lock lock = CacheFactory.getLock(from.toString(), directedPresencesCache);
        	try {
        		lock.lock();
        		directedPresences = directedPresencesCache.remove(from.toString());
        	} finally {
        		lock.unlock();
        	}
            
            if (directedPresences != null) {
                // Iterate over all the entities that the user sent a directed presence
                for (DirectedPresence directedPresence : directedPresences) {
                    for (String receiver : directedPresence.getReceivers()) {
                        Presence presence = update.createCopy();
                        presence.setTo(receiver);
                        localServer.getPresenceRouter().route(presence);
                    }
                }
                localDirectedPresences.remove(from.toString());
            }
        }
    }

    public boolean hasDirectPresence(JID ownerJID, JID recipientJID) {
        if (recipientJID == null) {
            return false;
        }
        Collection<DirectedPresence> directedPresences = directedPresencesCache.get(ownerJID.toString());
        if (directedPresences != null) {
            String recipient = recipientJID.toBareJID();
            for (DirectedPresence directedPresence : directedPresences) {
                for (String receiver : directedPresence.getReceivers()) {
                    if (receiver.contains(recipient)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * Removes directed presences sent to entities that are no longer available.
     */
    public void removedExpiredPresences() {
        Map<String, Collection<DirectedPresence>> copy =
                new HashMap<String, Collection<DirectedPresence>>(localDirectedPresences);
        for (Map.Entry<String, Collection<DirectedPresence>> entry : copy.entrySet()) {
            for (DirectedPresence directedPresence : entry.getValue()) {
                if (!routingTable.hasClientRoute(directedPresence.getHandler()) &&
                        !routingTable.hasComponentRoute(directedPresence.getHandler())) {
                    Collection<DirectedPresence> presences = localDirectedPresences.get(entry.getKey());
                    presences.remove(directedPresence);
                    if (presences.isEmpty()) {
                        localDirectedPresences.remove(entry.getKey());
                    }
                }
            }
        }
    }

    public void initialize(XMPPServer server) {
        super.initialize(server);
        localServer = server;
        rosterManager = server.getRosterManager();
        presenceManager = server.getPresenceManager();
        deliverer = server.getPacketDeliverer();
        messageStore = server.getOfflineMessageStore();
        sessionManager = server.getSessionManager();
        userManager = server.getUserManager();
        routingTable = server.getRoutingTable();
        directedPresencesCache = CacheFactory.createCache(PRESENCE_CACHE_NAME);
        // TODO Add as route listener (to remove direct presences info for removed routes). Mainly for c2s sessions which is uncommon.
        // Listen to cluster events
        ClusterManager.addListener(this);
    }

    public void joinedCluster() {
        // Populate directedPresencesCache with local content since when not in a cluster
        // we could still send directed presences to entities that when connected to a cluster
        // they will be replicated. An example would be MUC rooms.
        for (Map.Entry<String, Collection<DirectedPresence>> entry : localDirectedPresences.entrySet()) {
            if (entry.getValue().isEmpty()) {
                Log.warn("PresenceUpdateHandler - Skipping empty directed presences when joining cluster for sender: " +
                        entry.getKey());
                continue;
            }

        	// TODO perhaps we should not lock for every entry. Instead, lock it
			// once (using a LOCK_ALL global key), and handle iterations in
			// one go. We should first make sure that this doesn't lead to
			// deadlocks though! The tryLock() mechanism could be used to first
            // try one approach, but fall back on the other approach.
            Lock lock = CacheFactory.getLock(entry.getKey(), directedPresencesCache);
        	try {
        		lock.lock();
        		directedPresencesCache.put(entry.getKey(), entry.getValue());
        	} finally {
        		lock.unlock();
        	}
        }
    }

    public void joinedCluster(byte[] nodeID) {
        // Do nothing
    }

    public void leftCluster() {
        if (!XMPPServer.getInstance().isShuttingDown()) {
            // Populate directedPresencesCache with local content
            for (Map.Entry<String, Collection<DirectedPresence>> entry : localDirectedPresences.entrySet()) {
                if (entry.getValue().isEmpty()) {
                    Log.warn(
                            "PresenceUpdateHandler - Skipping empty directed presences when leaving cluster for sender: " +
                                    entry.getKey());
                    continue;
                }    

                
            	// TODO perhaps we should not lock for every entry. Instead, lock it
    			// once (using a LOCK_ALL global key), and handle iterations in
    			// one go. We should first make sure that this doesn't lead to
    			// deadlocks though! The tryLock() mechanism could be used to first
                // try one approach, but fall back on the other approach.
                Lock lock = CacheFactory.getLock(entry.getKey(), directedPresencesCache);
            	try {
            		lock.lock();
            		directedPresencesCache.put(entry.getKey(), entry.getValue());
            	} finally {
            		lock.unlock();
            	}
            }
        }
    }

    public void leftCluster(byte[] nodeID) {
        // Do nothing
    }

    public void markedAsSeniorClusterMember() {
        // Do nothing
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -