@GuardedBy("mutex")
    private void replaceFederatedOccupant(@Nullable final Occupant oldOccupant, @Nullable final Occupant newOccupant)
    {
        if (oldOccupant == null && newOccupant == null) {
            throw new IllegalArgumentException("Arguments 'oldOccupant' and 'newOccupant' cannot both be null (but were).");
        }
        if (oldOccupant != null && !oldOccupant.isFederated()) {
            throw new IllegalArgumentException("Argument 'oldOccupant' refers to a local/non-federated user '" + oldOccupant + "' (use #replaceLocalOccupant() instead).");
        }
        if (newOccupant != null && !newOccupant.isFederated()) {
            throw new IllegalArgumentException("Argument 'newOccupant' refers to a local/non-federated user '" + newOccupant + "' (use #replaceLocalOccupant() instead).");
        }

        if (oldOccupant != null) {
            federatedOccupants.computeIfPresent(oldOccupant.getRealJID(), (jid, occupants) -> {
                occupants.remove(oldOccupant);
                return occupants.isEmpty() ? null : occupants; // Delete if no occupants are left.
            });

            // When an occupant is being pinged, but removed from the node, cancel the ping.
            final TimerTask pendingPingTask = oldOccupant.getPendingPingTask();
            if (pendingPingTask != null) {
                Log.debug("Remove pending ping task for {} that is being deleted.", oldOccupant);
                TaskEngine.getInstance().cancelScheduledTask(pendingPingTask);
                oldOccupant.setPendingPingTask(null);
            }
        }
        if (newOccupant != null) {
            federatedOccupants.computeIfAbsent(newOccupant.getRealJID(), (n) -> new HashSet<>()).add(newOccupant);
        }
    }
Registers disappearance of an existing occupant, and/or appearance of a new occupant

This method maintains the two different occupant lookup tables, and keeps them in sync.

Calls to this method must be mode only under guard of a write lock that been obtained from {@link #mutex}.

This method <em>only</em> should be used for federated/non-local users. For local users, use
{@link #replaceLocalOccupant(Occupant, Occupant, NodeID)}.

@param oldOccupant An occupant that is to be removed from the registration of the referred node
@param newOccupant An occupant that is to be added to the registration of the referred node
xmppserver/src/main/java/org/jivesoftware/openfire/muc/spi/OccupantManager.java