- /*
- * Copyright 2004 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.apache.commons.collections.map;
-
- import java.io.Serializable;
- import java.util.Collection;
- import java.util.Iterator;
- import java.util.Map;
- import java.util.Set;
-
- import org.apache.commons.collections.IterableMap;
- import org.apache.commons.collections.MapIterator;
- import org.apache.commons.collections.keyvalue.MultiKey;
-
- /**
- * A <code>Map</code> implementation that uses multiple keys to map the value.
- * <p>
- * This class is the most efficient way to uses multiple keys to map to a value.
- * The best way to use this class is via the additional map-style methods.
- * These provide <code>get</code>, <code>containsKey</code>, <code>put</code> and
- * <code>remove</code> for individual keys which operate without extra object creation.
- * <p>
- * The additional methods are the main interface of this map.
- * As such, you will not normally hold this map in a variable of type <code>Map</code>.
- * <p>
- * The normal map methods take in and return a {@link MultiKey}.
- * If you try to use <code>put()</code> with any other object type a
- * <code>ClassCastException</code> is thrown. If you try to use <code>null</code> as
- * the key in <code>put()</code> a <code>NullPointerException</code> is thrown.
- * <p>
- * This map is implemented as a decorator of a <code>AbstractHashedMap</code> which
- * enables extra behaviour to be added easily.
- * <ul>
- * <li><code>MultiKeyMap.decorate(new LinkedMap())</code> creates an ordered map.
- * <li><code>MultiKeyMap.decorate(new LRUMap())</code> creates an least recently used map.
- * <li><code>MultiKeyMap.decorate(new ReferenceMap())</code> creates a garbage collector sensitive map.
- * </ul>
- * Note that <code>IdentityMap</code> and <code>ReferenceIdentityMap</code> are unsuitable
- * for use as the key comparison would work on the whole MultiKey, not the elements within.
- * <p>
- * As an example, consider a least recently used cache that uses a String airline code
- * and a Locale to lookup the airline's name:
- * <pre>
- * private MultiKeyMap cache = MultiKeyMap.decorate(new LRUMap(50));
- *
- * public String getAirlineName(String code, String locale) {
- * String name = (String) cache.get(code, locale);
- * if (name == null) {
- * name = getAirlineNameFromDB(code, locale);
- * cache.put(code, locale, name);
- * }
- * return name;
- * }
- * </pre>
- *
- * @since Commons Collections 3.1
- * @version $Revision: 1.3 $ $Date: 2004/06/07 21:00:58 $
- *
- * @author Stephen Colebourne
- */
- public class MultiKeyMap
- implements IterableMap, Serializable {
-
- /** Serialisation version */
- private static final long serialVersionUID = -1788199231038721040L;
-
- /** The decorated map */
- protected final AbstractHashedMap map;
-
- //-----------------------------------------------------------------------
- /**
- * Decorates the specified map to add the MultiKeyMap API and fast query.
- * The map must not be null and must be empty.
- *
- * @param map the map to decorate, not null
- * @throws IllegalArgumentException if the map is null or not empty
- */
- public static MultiKeyMap decorate(AbstractHashedMap map) {
- if (map == null) {
- throw new IllegalArgumentException("Map must not be null");
- }
- if (map.size() > 0) {
- throw new IllegalArgumentException("Map must be empty");
- }
- return new MultiKeyMap(map);
- }
-
- //-----------------------------------------------------------------------
- /**
- * Constructs a new MultiKeyMap that decorates a <code>HashedMap</code>.
- */
- public MultiKeyMap() {
- super();
- map = new HashedMap();
- }
-
- /**
- * Constructor that decorates the specified map and is called from
- * {@link #decorate(AbstractHashedMap)}.
- * The map must not be null and should be empty or only contain valid keys.
- * This constructor performs no validation.
- *
- * @param map the map to decorate
- */
- protected MultiKeyMap(AbstractHashedMap map) {
- super();
- this.map = map;
- }
-
- //-----------------------------------------------------------------------
- /**
- * Gets the value mapped to the specified multi-key.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @return the mapped value, null if no match
- */
- public Object get(Object key1, Object key2) {
- int hashCode = hash(key1, key2);
- AbstractHashedMap.HashEntry entry = map.data[map.hashIndex(hashCode, map.data.length)];
- while (entry != null) {
- if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2)) {
- return entry.getValue();
- }
- entry = entry.next;
- }
- return null;
- }
-
- /**
- * Checks whether the map contains the specified multi-key.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @return true if the map contains the key
- */
- public boolean containsKey(Object key1, Object key2) {
- int hashCode = hash(key1, key2);
- AbstractHashedMap.HashEntry entry = map.data[map.hashIndex(hashCode, map.data.length)];
- while (entry != null) {
- if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2)) {
- return true;
- }
- entry = entry.next;
- }
- return false;
- }
-
- /**
- * Stores the value against the specified multi-key.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @param value the value to store
- * @return the value previously mapped to this combined key, null if none
- */
- public Object put(Object key1, Object key2, Object value) {
- int hashCode = hash(key1, key2);
- int index = map.hashIndex(hashCode, map.data.length);
- AbstractHashedMap.HashEntry entry = map.data[index];
- while (entry != null) {
- if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2)) {
- Object oldValue = entry.getValue();
- map.updateEntry(entry, value);
- return oldValue;
- }
- entry = entry.next;
- }
-
- map.addMapping(index, hashCode, new MultiKey(key1, key2), value);
- return null;
- }
-
- /**
- * Removes the specified multi-key from this map.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @return the value mapped to the removed key, null if key not in map
- */
- public Object remove(Object key1, Object key2) {
- int hashCode = hash(key1, key2);
- int index = map.hashIndex(hashCode, map.data.length);
- AbstractHashedMap.HashEntry entry = map.data[index];
- AbstractHashedMap.HashEntry previous = null;
- while (entry != null) {
- if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2)) {
- Object oldValue = entry.getValue();
- map.removeMapping(entry, index, previous);
- return oldValue;
- }
- previous = entry;
- entry = entry.next;
- }
- return null;
- }
-
- /**
- * Gets the hash code for the specified multi-key.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @return the hash code
- */
- protected int hash(Object key1, Object key2) {
- int h = 0;
- if (key1 != null) {
- h ^= key1.hashCode();
- }
- if (key2 != null) {
- h ^= key2.hashCode();
- }
- h += ~(h << 9);
- h ^= (h >>> 14);
- h += (h << 4);
- h ^= (h >>> 10);
- return h;
- }
-
- /**
- * Is the key equal to the combined key.
- *
- * @param entry the entry to compare to
- * @param key1 the first key
- * @param key2 the second key
- * @return true if the key matches
- */
- protected boolean isEqualKey(AbstractHashedMap.HashEntry entry, Object key1, Object key2) {
- MultiKey multi = (MultiKey) entry.getKey();
- return
- multi.size() == 2 &&
- (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
- (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1)));
- }
-
- //-----------------------------------------------------------------------
- /**
- * Gets the value mapped to the specified multi-key.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @return the mapped value, null if no match
- */
- public Object get(Object key1, Object key2, Object key3) {
- int hashCode = hash(key1, key2, key3);
- AbstractHashedMap.HashEntry entry = map.data[map.hashIndex(hashCode, map.data.length)];
- while (entry != null) {
- if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3)) {
- return entry.getValue();
- }
- entry = entry.next;
- }
- return null;
- }
-
- /**
- * Checks whether the map contains the specified multi-key.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @return true if the map contains the key
- */
- public boolean containsKey(Object key1, Object key2, Object key3) {
- int hashCode = hash(key1, key2, key3);
- AbstractHashedMap.HashEntry entry = map.data[map.hashIndex(hashCode, map.data.length)];
- while (entry != null) {
- if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3)) {
- return true;
- }
- entry = entry.next;
- }
- return false;
- }
-
- /**
- * Stores the value against the specified multi-key.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @param value the value to store
- * @return the value previously mapped to this combined key, null if none
- */
- public Object put(Object key1, Object key2, Object key3, Object value) {
- int hashCode = hash(key1, key2, key3);
- int index = map.hashIndex(hashCode, map.data.length);
- AbstractHashedMap.HashEntry entry = map.data[index];
- while (entry != null) {
- if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3)) {
- Object oldValue = entry.getValue();
- map.updateEntry(entry, value);
- return oldValue;
- }
- entry = entry.next;
- }
-
- map.addMapping(index, hashCode, new MultiKey(key1, key2, key3), value);
- return null;
- }
-
- /**
- * Removes the specified multi-key from this map.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @return the value mapped to the removed key, null if key not in map
- */
- public Object remove(Object key1, Object key2, Object key3) {
- int hashCode = hash(key1, key2, key3);
- int index = map.hashIndex(hashCode, map.data.length);
- AbstractHashedMap.HashEntry entry = map.data[index];
- AbstractHashedMap.HashEntry previous = null;
- while (entry != null) {
- if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3)) {
- Object oldValue = entry.getValue();
- map.removeMapping(entry, index, previous);
- return oldValue;
- }
- previous = entry;
- entry = entry.next;
- }
- return null;
- }
-
- /**
- * Gets the hash code for the specified multi-key.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @return the hash code
- */
- protected int hash(Object key1, Object key2, Object key3) {
- int h = 0;
- if (key1 != null) {
- h ^= key1.hashCode();
- }
- if (key2 != null) {
- h ^= key2.hashCode();
- }
- if (key3 != null) {
- h ^= key3.hashCode();
- }
- h += ~(h << 9);
- h ^= (h >>> 14);
- h += (h << 4);
- h ^= (h >>> 10);
- return h;
- }
-
- /**
- * Is the key equal to the combined key.
- *
- * @param entry the entry to compare to
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @return true if the key matches
- */
- protected boolean isEqualKey(AbstractHashedMap.HashEntry entry, Object key1, Object key2, Object key3) {
- MultiKey multi = (MultiKey) entry.getKey();
- return
- multi.size() == 3 &&
- (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
- (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) &&
- (key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2)));
- }
-
- //-----------------------------------------------------------------------
- /**
- * Gets the value mapped to the specified multi-key.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @param key4 the fourth key
- * @return the mapped value, null if no match
- */
- public Object get(Object key1, Object key2, Object key3, Object key4) {
- int hashCode = hash(key1, key2, key3, key4);
- AbstractHashedMap.HashEntry entry = map.data[map.hashIndex(hashCode, map.data.length)];
- while (entry != null) {
- if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4)) {
- return entry.getValue();
- }
- entry = entry.next;
- }
- return null;
- }
-
- /**
- * Checks whether the map contains the specified multi-key.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @param key4 the fourth key
- * @return true if the map contains the key
- */
- public boolean containsKey(Object key1, Object key2, Object key3, Object key4) {
- int hashCode = hash(key1, key2, key3, key4);
- AbstractHashedMap.HashEntry entry = map.data[map.hashIndex(hashCode, map.data.length)];
- while (entry != null) {
- if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4)) {
- return true;
- }
- entry = entry.next;
- }
- return false;
- }
-
- /**
- * Stores the value against the specified multi-key.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @param key4 the fourth key
- * @param value the value to store
- * @return the value previously mapped to this combined key, null if none
- */
- public Object put(Object key1, Object key2, Object key3, Object key4, Object value) {
- int hashCode = hash(key1, key2, key3, key4);
- int index = map.hashIndex(hashCode, map.data.length);
- AbstractHashedMap.HashEntry entry = map.data[index];
- while (entry != null) {
- if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4)) {
- Object oldValue = entry.getValue();
- map.updateEntry(entry, value);
- return oldValue;
- }
- entry = entry.next;
- }
-
- map.addMapping(index, hashCode, new MultiKey(key1, key2, key3, key4), value);
- return null;
- }
-
- /**
- * Removes the specified multi-key from this map.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @param key4 the fourth key
- * @return the value mapped to the removed key, null if key not in map
- */
- public Object remove(Object key1, Object key2, Object key3, Object key4) {
- int hashCode = hash(key1, key2, key3, key4);
- int index = map.hashIndex(hashCode, map.data.length);
- AbstractHashedMap.HashEntry entry = map.data[index];
- AbstractHashedMap.HashEntry previous = null;
- while (entry != null) {
- if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4)) {
- Object oldValue = entry.getValue();
- map.removeMapping(entry, index, previous);
- return oldValue;
- }
- previous = entry;
- entry = entry.next;
- }
- return null;
- }
-
- /**
- * Gets the hash code for the specified multi-key.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @param key4 the fourth key
- * @return the hash code
- */
- protected int hash(Object key1, Object key2, Object key3, Object key4) {
- int h = 0;
- if (key1 != null) {
- h ^= key1.hashCode();
- }
- if (key2 != null) {
- h ^= key2.hashCode();
- }
- if (key3 != null) {
- h ^= key3.hashCode();
- }
- if (key4 != null) {
- h ^= key4.hashCode();
- }
- h += ~(h << 9);
- h ^= (h >>> 14);
- h += (h << 4);
- h ^= (h >>> 10);
- return h;
- }
-
- /**
- * Is the key equal to the combined key.
- *
- * @param entry the entry to compare to
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @param key4 the fourth key
- * @return true if the key matches
- */
- protected boolean isEqualKey(AbstractHashedMap.HashEntry entry, Object key1, Object key2, Object key3, Object key4) {
- MultiKey multi = (MultiKey) entry.getKey();
- return
- multi.size() == 4 &&
- (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
- (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) &&
- (key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2))) &&
- (key4 == null ? multi.getKey(3) == null : key4.equals(multi.getKey(3)));
- }
-
- //-----------------------------------------------------------------------
- /**
- * Gets the value mapped to the specified multi-key.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @param key4 the fourth key
- * @param key5 the fifth key
- * @return the mapped value, null if no match
- */
- public Object get(Object key1, Object key2, Object key3, Object key4, Object key5) {
- int hashCode = hash(key1, key2, key3, key4, key5);
- AbstractHashedMap.HashEntry entry = map.data[map.hashIndex(hashCode, map.data.length)];
- while (entry != null) {
- if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4, key5)) {
- return entry.getValue();
- }
- entry = entry.next;
- }
- return null;
- }
-
- /**
- * Checks whether the map contains the specified multi-key.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @param key4 the fourth key
- * @param key5 the fifth key
- * @return true if the map contains the key
- */
- public boolean containsKey(Object key1, Object key2, Object key3, Object key4, Object key5) {
- int hashCode = hash(key1, key2, key3, key4, key5);
- AbstractHashedMap.HashEntry entry = map.data[map.hashIndex(hashCode, map.data.length)];
- while (entry != null) {
- if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4, key5)) {
- return true;
- }
- entry = entry.next;
- }
- return false;
- }
-
- /**
- * Stores the value against the specified multi-key.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @param key4 the fourth key
- * @param key5 the fifth key
- * @param value the value to store
- * @return the value previously mapped to this combined key, null if none
- */
- public Object put(Object key1, Object key2, Object key3, Object key4, Object key5, Object value) {
- int hashCode = hash(key1, key2, key3, key4, key5);
- int index = map.hashIndex(hashCode, map.data.length);
- AbstractHashedMap.HashEntry entry = map.data[index];
- while (entry != null) {
- if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4, key5)) {
- Object oldValue = entry.getValue();
- map.updateEntry(entry, value);
- return oldValue;
- }
- entry = entry.next;
- }
-
- map.addMapping(index, hashCode, new MultiKey(key1, key2, key3, key4, key5), value);
- return null;
- }
-
- /**
- * Removes the specified multi-key from this map.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @param key4 the fourth key
- * @param key5 the fifth key
- * @return the value mapped to the removed key, null if key not in map
- */
- public Object remove(Object key1, Object key2, Object key3, Object key4, Object key5) {
- int hashCode = hash(key1, key2, key3, key4, key5);
- int index = map.hashIndex(hashCode, map.data.length);
- AbstractHashedMap.HashEntry entry = map.data[index];
- AbstractHashedMap.HashEntry previous = null;
- while (entry != null) {
- if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4, key5)) {
- Object oldValue = entry.getValue();
- map.removeMapping(entry, index, previous);
- return oldValue;
- }
- previous = entry;
- entry = entry.next;
- }
- return null;
- }
-
- /**
- * Gets the hash code for the specified multi-key.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @param key4 the fourth key
- * @param key5 the fifth key
- * @return the hash code
- */
- protected int hash(Object key1, Object key2, Object key3, Object key4, Object key5) {
- int h = 0;
- if (key1 != null) {
- h ^= key1.hashCode();
- }
- if (key2 != null) {
- h ^= key2.hashCode();
- }
- if (key3 != null) {
- h ^= key3.hashCode();
- }
- if (key4 != null) {
- h ^= key4.hashCode();
- }
- if (key5 != null) {
- h ^= key5.hashCode();
- }
- h += ~(h << 9);
- h ^= (h >>> 14);
- h += (h << 4);
- h ^= (h >>> 10);
- return h;
- }
-
- /**
- * Is the key equal to the combined key.
- *
- * @param entry the entry to compare to
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @param key4 the fourth key
- * @param key5 the fifth key
- * @return true if the key matches
- */
- protected boolean isEqualKey(AbstractHashedMap.HashEntry entry, Object key1, Object key2, Object key3, Object key4, Object key5) {
- MultiKey multi = (MultiKey) entry.getKey();
- return
- multi.size() == 5 &&
- (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
- (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) &&
- (key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2))) &&
- (key4 == null ? multi.getKey(3) == null : key4.equals(multi.getKey(3))) &&
- (key5 == null ? multi.getKey(4) == null : key5.equals(multi.getKey(4)));
- }
-
- //-----------------------------------------------------------------------
- /**
- * Removes all mappings where the first key is that specified.
- * <p>
- * This method removes all the mappings where the <code>MultiKey</code>
- * has one or more keys, and the first matches that specified.
- *
- * @param key1 the first key
- * @return true if any elements were removed
- */
- public boolean removeAll(Object key1) {
- boolean modified = false;
- MapIterator it = mapIterator();
- while (it.hasNext()) {
- MultiKey multi = (MultiKey) it.next();
- if (multi.size() >= 1 &&
- (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0)))) {
- it.remove();
- modified = true;
- }
- }
- return modified;
- }
-
- /**
- * Removes all mappings where the first two keys are those specified.
- * <p>
- * This method removes all the mappings where the <code>MultiKey</code>
- * has two or more keys, and the first two match those specified.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @return true if any elements were removed
- */
- public boolean removeAll(Object key1, Object key2) {
- boolean modified = false;
- MapIterator it = mapIterator();
- while (it.hasNext()) {
- MultiKey multi = (MultiKey) it.next();
- if (multi.size() >= 2 &&
- (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
- (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1)))) {
- it.remove();
- modified = true;
- }
- }
- return modified;
- }
-
- /**
- * Removes all mappings where the first three keys are those specified.
- * <p>
- * This method removes all the mappings where the <code>MultiKey</code>
- * has three or more keys, and the first three match those specified.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @return true if any elements were removed
- */
- public boolean removeAll(Object key1, Object key2, Object key3) {
- boolean modified = false;
- MapIterator it = mapIterator();
- while (it.hasNext()) {
- MultiKey multi = (MultiKey) it.next();
- if (multi.size() >= 3 &&
- (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
- (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) &&
- (key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2)))) {
- it.remove();
- modified = true;
- }
- }
- return modified;
- }
-
- /**
- * Removes all mappings where the first four keys are those specified.
- * <p>
- * This method removes all the mappings where the <code>MultiKey</code>
- * has four or more keys, and the first four match those specified.
- *
- * @param key1 the first key
- * @param key2 the second key
- * @param key3 the third key
- * @param key4 the fourth key
- * @return true if any elements were removed
- */
- public boolean removeAll(Object key1, Object key2, Object key3, Object key4) {
- boolean modified = false;
- MapIterator it = mapIterator();
- while (it.hasNext()) {
- MultiKey multi = (MultiKey) it.next();
- if (multi.size() >= 4 &&
- (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
- (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) &&
- (key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2))) &&
- (key4 == null ? multi.getKey(3) == null : key4.equals(multi.getKey(3)))) {
- it.remove();
- modified = true;
- }
- }
- return modified;
- }
-
- //-----------------------------------------------------------------------
- /**
- * Check to ensure that input keys are valid MultiKey objects.
- *
- * @param key the key to check
- */
- protected void checkKey(Object key) {
- if (key == null) {
- throw new NullPointerException("Key must not be null");
- }
- if (key instanceof MultiKey == false) {
- throw new ClassCastException("Key must be a MultiKey");
- }
- }
-
- /**
- * Clones the map without cloning the keys or values.
- *
- * @return a shallow clone
- */
- public Object clone() {
- return new MultiKeyMap((AbstractHashedMap) map.clone());
- }
-
- /**
- * Puts the key and value into the map, where the key must be a non-null
- * MultiKey object.
- *
- * @param key the non-null MultiKey object
- * @param value the value to store
- * @return the previous value for the key
- * @throws NullPointerException if the key is null
- * @throws ClassCastException if the key is not a MultiKey
- */
- public Object put(Object key, Object value) {
- checkKey(key);
- return map.put(key, value);
- }
-
- /**
- * Puts all the keys and values into this map.
- * Each key must be non-null and a MultiKey object.
- *
- * @param key the non-null MultiKey object
- * @param value the value to store
- * @return the previous value for the key
- * @throws NullPointerException if the mapToCopy or any key within is null
- * @throws ClassCastException if any key is not a MultiKey
- */
- public void putAll(Map mapToCopy) {
- for (Iterator it = mapToCopy.keySet().iterator(); it.hasNext();) {
- Object key = it.next();
- checkKey(key);
- }
- map.putAll(mapToCopy);
- }
-
- //-----------------------------------------------------------------------
- public MapIterator mapIterator() {
- return map.mapIterator();
- }
-
- public int size() {
- return map.size();
- }
-
- public boolean isEmpty() {
- return map.isEmpty();
- }
-
- public boolean containsKey(Object key) {
- return map.containsKey(key);
- }
-
- public boolean containsValue(Object value) {
- return map.containsValue(value);
- }
-
- public Object get(Object key) {
- return map.get(key);
- }
-
- public Object remove(Object key) {
- return map.remove(key);
- }
-
- public void clear() {
- map.clear();
- }
-
- public Set keySet() {
- return map.keySet();
- }
-
- public Collection values() {
- return map.values();
- }
-
- public Set entrySet() {
- return map.entrySet();
- }
-
- public boolean equals(Object obj) {
- if (obj == this) {
- return true;
- }
- return map.equals(obj);
- }
-
- public int hashCode() {
- return map.hashCode();
- }
-
- public String toString() {
- return map.toString();
- }
-
- }