public static <K extends Serializable, V, C extends Collection<V> & Serializable> Map<Boolean,Map<K, C>> removeValueFromMultiValuedCache( Cache<K, C> cache, V element )
    {
        // In some cache implementations, the entry-set is unmodifiable. To guard against potential
        // future changes of this implementation (that would make the implementation incompatible with
        // these cache implementations), the entry-set that's operated on in this implementation is
        // explicitly wrapped in an unmodifiable collection. That forces this implementation to be
        // compatible with the 'lowest common denominator'.
        final Set<Map.Entry<K, C>> entries = Collections.unmodifiableSet( cache.entrySet() );

        // contains all entries that were somehow changed.
        final Map<Boolean, Map<K, C>> result = new HashMap<>();
        result.put( false, new HashMap<>());
        result.put( true, new HashMap<>());

        for ( final Map.Entry<K, C> entry : entries )
        {
            final K key = entry.getKey();

            final Lock lock = cache.getLock( key );
            lock.lock();
            try
            {
                final C elements = entry.getValue();

                // Remove all instances of the element from the entry value.
                boolean changed = false;
                while ( elements.remove( element ) )
                {
                    changed = true;
                }

                if ( changed )
                {
                    if ( elements.isEmpty() )
                    {
                        // When after removal, the value is empty, remove the cache entry completely.
                        cache.remove( entry.getKey() );
                        result.get(false).put( entry.getKey(), elements );
                    }
                    else
                    {
                        // The cluster-based cache needs an explicit 'put' to cause the change to propagate.
                        cache.put( entry.getKey(), elements );
                        result.get(true).put( entry.getKey(), elements );
                    }
                }
            }
            finally
            {
                lock.unlock();
            }
        }
        return result;
    }
Removes all instances of the specified element from every collection that is a value of the cache.

When the element removed from the collection leaves that collection empty, the cache entry is removed completely.

The implementation of this method is designed to be compatible with both clustered as well as non-clustered caches.

The return value is a Map that contains all entries that were affected by the call. The returned has exactly two
keys, that each have a Map for its value.
- the Map that is the value of the 'false' key contains all entries that have been removed from the cache.
- the Map that is the value of the 'true' key contains all entries that have been modified.

@param cache   The cache from which to remove the element (cannot be null).
@param element The element to be removed (can be null only if the value-Collection supports null values).
@param <K> the type of key contained by the cache
@param <V> the type of value contained by the cache
@param <C> the type of collection contained by the cache
@return a map containing all affected cache entries (never null)
xmppserver/src/main/java/org/jivesoftware/util/cache/CacheUtil.java