private void add(K key, Set<NodeID> newNodesWithThisKey)
    {
        // Step 1 : update existing entries to the updated situation
        final Iterator<Map.Entry<NodeID, Set<K>>> iter = reverseCacheRepresentation.entrySet().iterator();
        while (iter.hasNext()) {
            final Map.Entry<NodeID, Set<K>> existingEntry = iter.next();
            final NodeID existingEntryNodeID = existingEntry.getKey();
            if (newNodesWithThisKey.contains(existingEntryNodeID)) {
                existingEntry.getValue().add(key);
            }
        }
        // Step 2 : add entries for node ids that were not in the reverse lookup before
        for (final NodeID nodeIdForWhichTheValueExists : newNodesWithThisKey) {
            if (!reverseCacheRepresentation.containsKey(nodeIdForWhichTheValueExists)) {
                reverseCacheRepresentation.computeIfAbsent(nodeIdForWhichTheValueExists, k -> new HashSet<>()).add(key);
            }
        }
    }
Cache entry listener implementation that maintains a reverse lookup map for the cache that is being observed, which
is used to identify what cluster nodes are the logical owner of a particular cache entry. This information is typically
useful in scenarios where a cluster node drops out of the cluster requiring the remaining nodes to have to inform
their connected entities of what resources have become unavailable.

This implementation uses a function (to be provided in the constructor) to calculate what cluster nodes 'own' a
corresponding entry. The function operates on the value of the cache. It is therefor required that listeners of this
type are registered using a configuration that includes entry values to be included in the event invocation. Null
values are not supported.
xmppserver/src/main/java/org/jivesoftware/util/cache/ReverseLookupComputingCacheEntryListener.java