public void process(@Nonnull final SyncLocalOccupantsAndSendJoinPresenceTask task)
    {
        Set<Occupant> oldLocalOccupants;

        mutex.writeLock().lock();
        try {
            final Map<JID, Set<Occupant>> jidSetMap = localOccupantsByNode.get(task.getOriginator());
            if (jidSetMap == null) {
                oldLocalOccupants = null;
            } else {
                oldLocalOccupants = jidSetMap.values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
            }
            Log.debug("We received a copy of {} local MUC occupants from node {}. We already had {} occupants in local registration for that node.", task.getOccupants().size(), task.getOriginator(), oldLocalOccupants == null ? 0 : oldLocalOccupants.size());

            if (oldLocalOccupants != null) {
                // Use defensive copy to prevent concurrent modification exceptions.
                oldLocalOccupants = new HashSet<>(oldLocalOccupants);
            }
            if (oldLocalOccupants != null) {
                Log.debug("Removing {} old local occupants", oldLocalOccupants.size());
                oldLocalOccupants.forEach(oldOccupant -> replaceLocalOccupant(oldOccupant, null, task.getOriginator()));
            }
            if (task.getOccupants() != null) {
                Log.debug("Adding {} new occupants", task.getOccupants().size());
                task.getOccupants().forEach(newOccupant -> {
                    if (newOccupant.isFederated()) {
                        replaceFederatedOccupant(null, newOccupant);
                    } else {
                        replaceLocalOccupant(null, newOccupant, task.getOriginator());
                    }
                });
            }
        } finally {
            mutex.writeLock().unlock(); // Unlock write, still hold read.
        }

        if (oldLocalOccupants != null) {
            if (oldLocalOccupants.equals(task.getOccupants().stream().filter(occupant -> !occupant.isFederated()).collect(Collectors.toSet()))) {
                Log.info("We received a copy of local MUC occupants from node {}, but we already had this information. This hints at a possible inefficient sharing of data across the cluster.", task.getOriginator());
            } else {
                Log.warn("We received a copy of local MUC occupants from node {}, but we already had occupants for this node. However, the new data is different from the old data!", task.getOriginator());
            }
        }
    }
Used by other nodes telling us about all of their occupants.

@param task Cluster task that informs of occupants on a remote node.
xmppserver/src/main/java/org/jivesoftware/openfire/muc/spi/OccupantManager.java