/*
* JBoss, Home of Professional Open Source
* Copyright 2009 Red Hat Inc. and/or its affiliates and other
* contributors as indicated by the @author tags. All rights reserved.
* See the copyright.txt in the distribution for a full listing of
* individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.infinispan.atomic;
import org.infinispan.AdvancedCache;
import org.infinispan.Cache;
import org.infinispan.context.Flag;
import org.infinispan.context.FlagContainer;
import java.util.Collections;
import java.util.Map;
import static org.infinispan.util.Immutables.immutableMapWrap;
/**
* A helper that locates or safely constructs and registers atomic maps with a given cache. This should be the
* <b>only</b> way AtomicMaps are created/retrieved, to prevent concurrent creation, registration and possibly
* overwriting of such a map within the cache.
*
* @author Manik Surtani
* @see AtomicMap
* @since 4.0
*/
public class AtomicMapLookup {
/**
* Retrieves an atomic map from a given cache, stored under a given key. If an atomic map did not exist, one is
* created and registered in an atomic fashion.
*
* @param cache underlying cache
* @param key key under which the atomic map exists
* @param <MK> key param of the cache
* @param <K> key param of the AtomicMap
* @param <V> value param of the AtomicMap
* @return an AtomicMap
*/
public static <MK, K, V> AtomicMap<K, V> getAtomicMap(Cache<MK, ?> cache, MK key) {
return getAtomicMap(cache, key, true);
}
/**
* Retrieves a fine grained atomic map from a given cache, stored under a given key. If a fine grained atomic map did
* not exist, one is created and registered in an atomic fashion.
*
* @param cache underlying cache
* @param key key under which the atomic map exists
* @param <MK> key param of the cache
* @param <K> key param of the AtomicMap
* @param <V> value param of the AtomicMap
* @return an AtomicMap
*/
public static <MK, K, V> FineGrainedAtomicMap<K, V> getFineGrainedAtomicMap(Cache<MK, ?> cache, MK key) {
return getFineGrainedAtomicMap(cache, key, true);
}
/**
* Retrieves an atomic map from a given cache, stored under a given key.
*
* @param cache underlying cache
* @param key key under which the atomic map exists
* @param createIfAbsent if true, a new atomic map is created if one doesn't exist; otherwise null is returned if the
* map didn't exist.
* @param <MK> key param of the cache
* @param <K> key param of the AtomicMap
* @param <V> value param of the AtomicMap
* @return an AtomicMap, or null if one did not exist.
*/
public static <MK, K, V> AtomicMap<K, V> getAtomicMap(Cache<MK, ?> cache, MK key, boolean createIfAbsent) {
return (AtomicMap<K, V>) getMap(cache, key, createIfAbsent, false, null);
}
/**
* Retrieves an atomic map from a given cache, stored under a given key.
*
* @param cache underlying cache
* @param key key under which the atomic map exists
* @param flagContainer a container to pass in per-invocation flags to the underlying cache. May be null if no
* flags are used.
* @param <MK> key param of the cache
* @param <K> key param of the AtomicMap
* @param <V> value param of the AtomicMap
* @return an AtomicMap, or null if one did not exist.
*/
public static <MK, K, V> AtomicMap<K, V> getAtomicMap(Cache<MK, ?> cache, MK key, FlagContainer flagContainer) {
return (AtomicMap<K, V>) getMap(cache, key, true, false, flagContainer);
}
/**
* Retrieves an atomic map from a given cache, stored under a given key.
*
* @param cache underlying cache
* @param key key under which the atomic map exists
* @param createIfAbsent if true, a new atomic map is created if one doesn't exist; otherwise null is returned if the
* map didn't exist.
* @param <MK> key param of the cache
* @param <K> key param of the AtomicMap
* @param <V> value param of the AtomicMap
* @return an AtomicMap, or null if one did not exist.
*/
public static <MK, K, V> FineGrainedAtomicMap<K, V> getFineGrainedAtomicMap(Cache<MK, ?> cache, MK key, boolean createIfAbsent) {
return (FineGrainedAtomicMap<K, V>) getMap(cache, key, createIfAbsent, true, null);
}
/**
* Retrieves an atomic map from a given cache, stored under a given key.
*
*
* @param cache underlying cache
* @param key key under which the atomic map exists
* @param createIfAbsent if true, a new atomic map is created if one doesn't exist; otherwise null is returned if the
* map didn't exist.
* @param fineGrained if true, and createIfAbsent is true then created atomic map will be fine grained.
* @param flagContainer
* @return an AtomicMap, or null if one did not exist.
*/
@SuppressWarnings("unchecked")
private static <MK, K, V> Map<K, V> getMap(Cache<MK, ?> cache, MK key, boolean createIfAbsent, boolean fineGrained, FlagContainer flagContainer) {
Object value = cache.get(key);
if (value == null) {
if (createIfAbsent)
value = AtomicHashMap.newInstance((Cache<Object,Object>) cache, key);
else return null;
}
AtomicHashMap<K, V> castValue = (AtomicHashMap<K, V>) value;
AtomicHashMapProxy<K, V> proxy =
castValue.getProxy((AdvancedCache<Object,Object>) cache.getAdvancedCache(), key, fineGrained, flagContainer);
boolean typeSwitchAttempt = proxy instanceof FineGrainedAtomicHashMapProxy != fineGrained;
if (typeSwitchAttempt) {
throw new IllegalArgumentException("Cannot switch type of previously used " + value
+ " from " + (fineGrained ? "regular to fine-grained!" : "fine-grained to regular!"));
}
return proxy;
}
/**
* Retrieves an atomic map from a given cache, stored under a given key, for reading only. The atomic map returned
* will not support updates, and if the map did not in fact exist, an empty map is returned.
*
* @param cache underlying cache
* @param key key under which the atomic map exists
* @param <MK> key param of the cache
* @param <K> key param of the AtomicMap
* @param <V> value param of the AtomicMap
* @return an immutable, read-only map
*/
public static <MK, K, V> Map<K, V> getReadOnlyAtomicMap(Cache<MK, ?> cache, MK key) {
AtomicMap<K, V> am = getAtomicMap(cache, key, false);
if (am == null)
return Collections.emptyMap();
else
return immutableMapWrap(am);
}
/**
* Removes the atomic map associated with the given key from the underlying cache.
*
* @param cache underlying cache
* @param key key under which the atomic map exists
* @param <MK> key param of the cache
*/
public static <MK> void removeAtomicMap(Cache<MK, ?> cache, MK key) {
cache.getAdvancedCache().withFlags(Flag.SKIP_REMOTE_LOOKUP, Flag.SKIP_CACHE_LOAD).remove(key);
}
}