/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is the Kowari Metadata Store.
*
* The Initial Developer of the Original Code is Plugged In Software Pty
* Ltd (http://www.pisoftware.com, mailto:info@pisoftware.com). Portions
* created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
* Plugged In Software Pty Ltd. All Rights Reserved.
*
* Contributor(s): N/A.
*
* [NOTE: The text of this Exhibit A may differ slightly from the text
* of the notices in the Source Code files of the Original Code. You
* should use the text of this Exhibit A rather than the text found in the
* Original Code Source Code for Your Modifications.]
*
*/
package org.mulgara.util;
// Java 2 standard packages
import java.util.*;
import org.mulgara.util.functional.C;
/**
* A wrapper for {@link Map}s which makes it convenient to deal with keys that
* map to multiple values.
*
* @author <a href="http://staff.pisoftware.com/raboczi/">Simon Raboczi</a>
* @copyright ©2001 <a href="http://www.pisoftware.com/">Plugged In
* Software Pty Ltd</a>
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
public class Multimap<K,V> implements Map<K,V> {
protected Map<K,Set<V>> map;
/**
* Constructor.
*
* @param map the underlying {@link Map}, whose values will be {@link Set}s of
* values
*/
public Multimap(Map<K,Set<V>> map) {
this.map = map;
}
//
// Methods overriding the MapWrapper
//
// TODO - the performance is linear in the number of keys; could improve
/**
* METHOD TO DO
*
* @param value PARAMETER TO DO
* @return RETURNED VALUE TO DO
*/
public boolean containsValue(Object value) {
for (Iterator<Set<V>> i = map.values().iterator(); i.hasNext();) {
if (i.next().contains(value)) return true;
}
return false;
}
/**
* METHOD TO DO
*
* @param key PARAMETER TO DO
* @param value PARAMETER TO DO
* @return RETURNED VALUE TO DO
*/
public V put(K key, V value) {
Set<V> values = map.get(key);
if (values == null) {
values = new HashSet<V>();
}
V old = values.contains(value) ? value : null;
values.add(value);
map.put(key, values);
return old;
}
/**
* Remove an object from being mapped to a specified key.
*
* @param key the key to remove the mapping from
* @param value the value to remove from the mapping
* @return whether the object existed and was unmapped
*/
public boolean removeMapping(K key, V value) {
Set<V> values = map.get(key);
if (values != null) {
boolean removed = values.remove(value);
if (values.isEmpty()) map.remove(key);
return removed;
} else {
return false;
}
}
/**
* METHOD TO DO
*
* @return RETURNED VALUE TO DO
*/
public Collection<V> values() {
Set<V> result = new HashSet<V>();
for (Iterator<Set<V>> i = map.values().iterator(); i.hasNext();) {
result.addAll(i.next());
}
return result;
}
@Override
public void clear() {
map.clear();
}
@Override
public boolean containsKey(Object key) {
return map.containsKey(key);
}
@Override
public Set<java.util.Map.Entry<K, V>> entrySet() {
Set<Map.Entry<K, V>> entries = new HashSet<Map.Entry<K, V>>();
for (Map.Entry<K,Set<V>> entry: map.entrySet()) {
for (V value: entry.getValue()) {
entries.add(new KV(entry.getKey(), value));
}
}
return entries;
}
/**
* This once broke the interface by returning a Set. Now it meets the interface
* but is useless.
* @see java.util.Map#get(java.lang.Object)
*/
@Override
public V get(Object key) {
return C.first(map.get(key));
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public Set<K> keySet() {
return map.keySet();
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
for (Map.Entry<? extends K, ? extends V> e: m.entrySet()) {
put(e.getKey(), e.getValue());
}
}
@Override
public V remove(Object key) {
Set<V> v = map.remove(key);
return v == null ? null : C.first(v);
}
@Override
public int size() {
int total = 0;
for (Set<V> v: map.values()) total += v.size();
return total;
}
class KV implements Map.Entry<K,V> {
K key;
V value;
KV(K k, V v) {
key = k;
value = v;
}
@Override
public K getKey() { return key; }
@Override
public V getValue() { return value; }
@Override
public V setValue(V v) {
V tmp = value;
value = v;
return tmp;
}
}
}