package javolution.util;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import javolution.context.LocalContext;
/**
* <p> This class represents a map which can be temporarily modified without
* impacting other threads ({@link LocalContext scoped} changes).</p>
*
* <p> Operation on instances of this class are thread-safe.
* For example:
* public class XMLFormat {
* static LocalMap<Class, XMLFormat> CLASS_TO_FORMAT = new LocalMap<Class, XMLFormat>();
* public static void setFormat(Class forClass, XMLFormat that) {
* CLASS_TO_FORMAT.put(forClass, that); // No synchronization required.
* }
* public static XMLFormat getInstance(Class forClass) {
* return CLASS_TO_FORMAT.get(forClass); // No synchronization required.
* }
* }
* public void main(String[] args) {
* // Sets default (global settings).
* XMLFormat.setFormat(Foo.class, xFormat);
* XMLFormat.setFormat(Bar.class, yFormat);
* }
* ... // Another thread.
* LocalContext.enter();
* try { // Use of local context to avoid impacting other threads.
* XMLFormat.setFormat(Foo.class, zFormat);
* XMLFormat.getInstance(Foo.class); // Returns zFormat
* XMLFormat.getInstance(Bar.class); // Returns yFormat (inherited)
* } finally {
* LocalContext.exit();
* }
* getInstance(Foo.class); // Returns xFormat
* [/code]</p>
*
* <p> <b>Note:</b> Because key-value mappings are inherited, the semantic of
* {@link #remove} and {@link #clear} is slightly modified (association with
* <code>null</code> values instead of removing the entries).</p>
*
* @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
* @version 3.7, January 27, 2005
*/
public final class LocalMap <K,V> implements Map <K,V> {
/**
* Holds the fast map reference (shared map).
*/
private final LocalContext.Reference _mapRef
= new LocalContext.Reference(new FastMap().shared());
/**
* Default constructor.
*/
public LocalMap() {
}
/**
* Sets the key comparator for this local map.
*
* @param keyComparator the key comparator.
* @return <code>this</code>
*/
public LocalMap <K,V> setKeyComparator(FastComparator <? super K> keyComparator) {
localMap().setKeyComparator(keyComparator);
return this;
}
/**
* Sets the value comparator for this local map.
*
* @param valueComparator the value comparator.
* @return <code>this</code>
*/
public LocalMap <K,V> setValueComparator(FastComparator <? super V> valueComparator) {
localMap().setValueComparator(valueComparator);
return this;
}
/**
* Sets the default value for the specified key (typically done at
* initialization).
*
* @param key the key with which the specified value is to be associated.
* @param defaultValue the default value to be associated with the
* specified key.
* @return the previous default value associated with specified key, or
* <code>null</code> if there was no mapping for key. A
* <code>null</code> return can also indicate that the map
* previously associated <code>null</code> with the specified key.
* @throws NullPointerException if the key is <code>null</code>.
*/
public V putDefault( K key, V defaultValue) {
return ( V ) ((FastMap) _mapRef.getDefault()).put(key,
defaultValue);
}
/**
* Returns the default value for the specified key.
*
* @param key the key with which the default value is associated.
* @return the default value associated with specified key, or
* <code>null</code> if there was no mapping for the key.
* @throws NullPointerException if the key is <code>null</code>.
*/
public V getDefault( K key) {
return ( V ) ((FastMap) _mapRef.getDefault()).get(key);
}
/**
* Returns the number of key-value mappings in this map.
*
* @return this map's size.
*/
public int size() {
return ((FastMap) _mapRef.get()).size();
}
/**
* Indicates if this map contains no key-value mappings.
*
* @return <code>true</code> if this map contains no key-value mappings;
* <code>false</code> otherwise.
*/
public boolean isEmpty() {
return ((FastMap) _mapRef.get()).isEmpty();
}
/**
* Indicates if this map contains a mapping for the specified key.
*
* @param key the key whose presence in this map is to be tested.
* @return <code>true</code> if this map contains a mapping for the
* specified key; <code>false</code> otherwise.
* @throws NullPointerException if the key is <code>null</code>.
*/
public boolean containsKey(Object key) {
return ((FastMap) _mapRef.get()).containsKey(key);
}
/**
* Indicates if this map associates one or more keys to the
* specified value.
*
* @param value the value whose presence in this map is to be tested.
* @return <code>true</code> if this map maps one or more keys to the
* specified value.
* @throws NullPointerException if the key is <code>null</code>.
*/
public boolean containsValue(Object value) {
return ((FastMap) _mapRef.get()).containsValue(value);
}
/**
* Returns the value to which this map associates the specified key.
*
* @param key the key whose associated value is to be returned.
* @return the value to which this map maps the specified key, or
* <code>null</code> if there is no mapping for the key.
* @throws NullPointerException if key is <code>null</code>.
*/
public V get(Object key) {
return ( V ) ((FastMap) _mapRef.get()).get(key);
}
/**
* Associates the specified value with the specified key in this map.
*
* @param key the key with which the specified value is to be associated.
* @param value the value to be associated with the specified key.
* @return the previous value associated with specified key, or
* <code>null</code> if there was no mapping for key. A
* <code>null</code> return can also indicate that the map
* previously associated <code>null</code> with the specified key.
* @throws NullPointerException if the key is <code>null</code>.
*/
public V put( K key, V value) {
return ( V ) localMap().put(key, value);
}
/**
* Copies all of the mappings from the specified map to this map.
*
* @param map the mappings to be stored in this map.
* @throws NullPointerException the specified map is <code>null</code>,
* or the specified map contains <code>null</code> keys.
*/
public void putAll(Map <? extends K, ? extends V> map) {
localMap().putAll(map);
}
/**
* Removes the mapping for this key from this map if present
* (sets the local value to <code>null</code>).
*
* @param key the key whose value is set to <code>null</code>
* @return <code>put(key, null)</code>
* @throws NullPointerException if the key is <code>null</code>.
*/
public V remove(Object key) {
return put(( K )key, null);
}
/**
* Removes all mappings from this map (sets the local values to
* <code>null</code>).
*/
public void clear() {
FastMap localMap = localMap();
for (FastMap.Entry e = localMap.head(), end = localMap.tail(); (e = (FastMap.Entry) e.getNext()) != end;) {
e.setValue(null);
}
}
/**
* Returns a {@link FastCollection} view of the keys contained in this map.
*
* @return a set view of the keys contained in this map
* (instance of {@link FastCollection}).
*/
public Set <K> keySet() {
return localMap().keySet();
}
/**
* Returns a {@link FastCollection} view of the values contained in this
* map.
*
* @return a collection view of the values contained in this map
* (instance of {@link FastCollection}).
*/
public Collection <V> values() {
return localMap().values();
}
/**
* Returns a {@link FastCollection} view of the mappings contained in this
* map.
*
* @return a collection view of the mappings contained in this map
* (instance of {@link FastCollection}).
*/
public Set <Map.Entry<K,V>> entrySet() {
return localMap().entrySet();
}
/**
* Returns the local map or creates one on the stack and populates
* it from inherited settings.
*
* @return a shared fast map belonging to the current local context.
*/
private FastMap <K,V> localMap() {
FastMap localMap = (FastMap) _mapRef.getLocal();
return (localMap != null) ? localMap : newLocalMap();
}
private FastMap newLocalMap() {
FastMap parentMap = (FastMap) _mapRef.get();
FastMap localMap = FastMap.newInstance();
localMap.shared();
localMap.setKeyComparator(parentMap.getKeyComparator());
localMap.setValueComparator(parentMap.getValueComparator());
localMap.putAll(parentMap);
_mapRef.set(localMap);
return localMap;
}
}