/*
* MapKeyMap.java
* Copyright 2008 (C) James Dempsey
*
* This library 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 library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Created on 11/09/2008 23:20:54
*
* $Id: $
*/
package pcgen.cdom.util;
import java.util.Map;
import java.util.Set;
import pcgen.base.util.DoubleKeyMap;
import pcgen.cdom.enumeration.MapKey;
/**
* This encapsulates a DoubleKeyMap in a typesafe and value-semantic way.
*
* Specifically, when Generics are properly used by a class using a MapKeyMap,
* this class ensures that any MapKey will only return a Map of the same Generic
* type as the MapKey. Note this relationship is only enforced with Generics,
* and could be violated if Generics are not properly used.
*
* This Class also is reference-semantic with respect to the Maps. In other
* words, the modification of any Collection returned by a MapKeyMap will not
* impact the internal contents of the MapKeyMap. Also, any Collection used as a
* parameter to a method is not stored directly, the Collection can be modified
* after the method has returned without impacting the internal contents of the
* MapKeyMap.
*
* **NOTE** This class is NOT thread safe.
*
*
* @author James Dempsey <jdempsey@users.sourceforge.net>
*/
public class MapKeyMap
{
/*
* Much as for ListKeyMapToList.map this must remain generic. See Tom's
* comment in that class for the full explanation.
*/
/** The internal storage of this MapKeyMap. */
@SuppressWarnings("rawtypes")
private final DoubleKeyMap map = new DoubleKeyMap();
/**
* Copies the key/value combinations from the given MapKeyMap into this
* MapKeyMap. If this MapKeyMap already contained a mapping for the any of
* the key combinations in the given MapKeyMap, the previous value is
* overwritten.
*
* @param mkm
* The MapKeyMap for which the key/value combinations should be
* placed into this MapKeyMap
*
* @throws NullPointerException
* if the given MapKeyMap is null
*/
@SuppressWarnings("unchecked")
public final void putAll(MapKeyMap mkm)
{
map.putAll(mkm.map);
}
/**
* Adds the given value to the List for the given ListKey. The null value
* cannot be used as a key in a MapKeyMap. This method will automatically
* initialize the map for the given primary key if there is not already a
* Map for that primary key.
*
* This method is reference-semantic and this MapKeyMap will maintain a
* strong reference to both the key object and the value object given as
* arguments to this method.
*
* @param key1
* The MapKey indicating which Map the given object should be
* added to.
* @param value
* The value to be added to the List for the given key.
*/
@SuppressWarnings("unchecked")
public <K, V> V addToMapFor(MapKey<K, V> key1, K key2, V value)
{
return (V) map.put(key1, key2, value);
}
/**
* Returns true if this MapKeyMap contains a Map for the given MapKey. This
* method returns false if the given key is not in this MapKeyMap.
*
* This method is value-semantic in that no changes are made to the object
* passed into the method.
*
* @param key
* The MapKey being tested.
* @return true if this MapKeyMap contains a Map for the given key; false
* otherwise.
*/
@SuppressWarnings("unchecked")
public boolean containsMapFor(MapKey<?, ?> key)
{
return map.containsKey(key);
}
/**
* Returns a copy of the List contained in this MapKeyMap for the given
* ListKey. This method returns null if the given key is not in this
* MapKeyMap.
*
* This method is value-semantic in that no changes are made to the object
* passed into the method and ownership of the returned List is transferred
* to the class calling this method.
*
* @param key1
* The MapKeyMap to find
* @param key2
* The ListKey for which a copy of the list should be returned.
* @return a copy of the List contained in this MapKeyMap for the given key;
* null if the given key is not a key in this MapKeyMap.
*/
@SuppressWarnings("unchecked")
public <K, V> V get(MapKey<K, V> key1, K key2)
{
return (V) map.get(key1, key2);
}
/**
* Returns a copy of the List contained in this MapKeyMap for the given
* ListKey. This method returns null if the given key is not in this
* MapKeyMap.
*
* This method is value-semantic in that no changes are made to the object
* passed into the method and ownership of the returned List is transferred
* to the class calling this method.
*
* @param key
* The ListKey for which a copy of the list should be returned.
* @return a copy of the List contained in this MapKeyMap for the given key;
* null if the given key is not a key in this MapKeyMap.
*/
@SuppressWarnings("unchecked")
public <K, V> Map<K, V> getMapFor(MapKey<K, V> key)
{
return map.getMapFor(key);
}
/**
* Returns a Set of the secondary keys for the given primary key in this
* MapKeyMap. This method returns an empty set if the given key is not in
* this MapKeyMap.
*
* Note: This Set is reference-semantic. The ownership of the Set is
* transferred to the calling Object; therefore, changes to the returned Set
* will NOT impact the MapKeyMap.
*
* @param key
* The MapKey for which a copy of the keys should be returned.
* @return A <tt>Set</tt> of secondary key objects for the given primary
* key.
*/
@SuppressWarnings("unchecked")
public <K, V> Set<K> getKeysFor(MapKey<K, V> key)
{
return map.getSecondaryKeySet(key);
}
/**
* Removes the given value from the map for the given MapKey. Returns true
* if the value was successfully removed from the map for the given MapKey.
* Returns false if there is not a map for the given MapKey or if the map
* for the given MapKey did not contain the given secondary key.
*
* @param key1
* The MapKey indicating which Map the given object should be
* removed from
* @param key2
* The key to be removed from the Map
* @return true if the key and its associated value were successfully
* removed from the map; false otherwise
*/
@SuppressWarnings("unchecked")
public <K, V> boolean removeFromMapFor(MapKey<K, V> key1, K key2)
{
return map.remove(key1, key2) != null;
}
/**
* Removes the List for the given ListKey. Note there is no requirement that
* the list for the given key be empty before this method is called.
*
* Ownership of the returned Map is transferred to the object calling this
* method.
*
* @return The Map which this MapKeyMap previous mapped the given key
*/
@SuppressWarnings("unchecked")
public <K, V> Map<K, V> removeMapFor(MapKey<K, V> key)
{
return map.removeAll(key);
}
/**
* Returns a Set indicating the Keys of this MapKeyMap. Ownership of the Set
* is transferred to the calling Object, no association is kept between the
* Set and this MapKeyMap. (Thus, removal of a key from the returned Set
* will not remove that key from this MapKeyMap)
*
* NOTE: This method returns all of the keys this MapKeyMap contains. It
* DOES NOT determine whether the Lists defined for the keys are empty.
* Therefore, it is possible that this MapKeyMap contains one or more keys,
* and all of the lists associated with those keys are empty, yet this
* method will return a non-zero length Set.
*
* @return a Set containing the keys in this MapKeyMap
*/
@SuppressWarnings("unchecked")
public Set<MapKey<?, ?>> getKeySet()
{
return map.getKeySet();
}
/**
* Returns true if this structure contains no Maps.
*
* @return true if this structure contains no Maps; false otherwise
*/
public boolean isEmpty()
{
return map.isEmpty();
}
/**
* Returns the consistent-with-equals hashCode for this MapKeyMap.
*
* @return the int
*
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode()
{
return map.hashCode();
}
/**
* Returns true if this MapKeyMap is equal to the given Object.
*
* Note that equality as defined by this method is both a class of MapKeyMap
* and equality of contents of the MapKeyMap.
*
* @param obj
* the o
*
* @return true, if equals
*
* @see java.lang.Object#equals(Object)
*/
@Override
public boolean equals(Object obj)
{
return obj instanceof MapKeyMap && map.equals(((MapKeyMap) obj).map);
}
}