/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program 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 distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*
*/
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* A <tt>Map</tt> where keys are compared by object identity,
* rather than <tt>equals()</tt>.
*/
public final class IdentityMap implements Map {
private final Map map;
private transient Map.Entry[] entryArray = new Map.Entry[0];
private transient boolean dirty = false;
/**
* Return a new instance of this class, with an undefined
* iteration order.
*
* @param size The size of the map
* @return Map
*/
public static Map instantiate(int size) {
return new IdentityMap( new HashMap( size ) );
}
/**
* Return a new instance of this class, with iteration
* order defined as the order in which entries were added
*
* @param size The size of the map to create
* @return
*/
public static Map instantiateSequenced(int size) {
return new IdentityMap( new LinkedHashMap( size ) );
}
/**
* Private ctor used in serialization.
*
* @param underlyingMap The delegate map.
*/
private IdentityMap(Map underlyingMap) {
map = underlyingMap;
dirty = true;
}
/**
* Return the map entries (as instances of <tt>Map.Entry</tt> in a collection that
* is safe from concurrent modification). ie. we may safely add new instances to
* the underlying <tt>Map</tt> during iteration of the <tt>entries()</tt>.
*
* @param map
* @return Collection
*/
public static Map.Entry[] concurrentEntries(Map map) {
return ( (IdentityMap) map ).entryArray();
}
public static List entries(Map map) {
return ( (IdentityMap) map ).entryList();
}
public static Iterator keyIterator(Map map) {
return ( (IdentityMap) map ).keyIterator();
}
public Iterator keyIterator() {
return new KeyIterator( map.keySet().iterator() );
}
public static final class IdentityMapEntry implements java.util.Map.Entry {
IdentityMapEntry(Object key, Object value) {
this.key=key;
this.value=value;
}
private Object key;
private Object value;
public Object getKey() {
return key;
}
public Object getValue() {
return value;
}
public Object setValue(Object value) {
Object result = this.value;
this.value = value;
return result;
}
}
public static final class IdentityKey implements Serializable {
private Object key;
IdentityKey(Object key) {
this.key=key;
}
public boolean equals(Object other) {
return key == ( (IdentityKey) other ).key;
}
public int hashCode() {
return System.identityHashCode(key);
}
public String toString() {
return key.toString();
}
public Object getRealKey() {
return key;
}
}
public int size() {
return map.size();
}
public boolean isEmpty() {
return map.isEmpty();
}
public boolean containsKey(Object key) {
IdentityKey k = new IdentityKey(key);
return map.containsKey(k);
}
public boolean containsValue(Object val) {
return map.containsValue(val);
}
public Object get(Object key) {
IdentityKey k = new IdentityKey(key);
return map.get(k);
}
public Object put(Object key, Object value) {
dirty = true;
return map.put( new IdentityKey(key), value );
}
public Object remove(Object key) {
dirty = true;
IdentityKey k = new IdentityKey(key);
return map.remove(k);
}
public void putAll(Map otherMap) {
Iterator iter = otherMap.entrySet().iterator();
while ( iter.hasNext() ) {
Map.Entry me = (Map.Entry) iter.next();
put( me.getKey(), me.getValue() );
}
}
public void clear() {
dirty = true;
entryArray = null;
map.clear();
}
public Set keySet() {
// would need an IdentitySet for this!
throw new UnsupportedOperationException();
}
public Collection values() {
return map.values();
}
public Set entrySet() {
Set set = new HashSet( map.size() );
Iterator iter = map.entrySet().iterator();
while ( iter.hasNext() ) {
Map.Entry me = (Map.Entry) iter.next();
set.add( new IdentityMapEntry( ( (IdentityKey) me.getKey() ).key, me.getValue() ) );
}
return set;
}
public List entryList() {
ArrayList list = new ArrayList( map.size() );
Iterator iter = map.entrySet().iterator();
while ( iter.hasNext() ) {
Map.Entry me = (Map.Entry) iter.next();
list.add( new IdentityMapEntry( ( (IdentityKey) me.getKey() ).key, me.getValue() ) );
}
return list;
}
public Map.Entry[] entryArray() {
if (dirty) {
entryArray = new Map.Entry[ map.size() ];
Iterator iter = map.entrySet().iterator();
int i=0;
while ( iter.hasNext() ) {
Map.Entry me = (Map.Entry) iter.next();
entryArray[i++] = new IdentityMapEntry( ( (IdentityKey) me.getKey() ).key, me.getValue() );
}
dirty = false;
}
return entryArray;
}
/**
* Workaround for a JDK 1.4.1 bug where <tt>IdentityHashMap</tt>s are not
* correctly deserialized.
*
* @param map
* @return Object
*/
public static Object serialize(Map map) {
return ( (IdentityMap) map ).map;
}
/**
* Workaround for a JDK 1.4.1 bug where <tt>IdentityHashMap</tt>s are not
* correctly deserialized.
*
* @param o
* @return Map
*/
public static Map deserialize(Object o) {
return new IdentityMap( (Map) o );
}
public String toString() {
return map.toString();
}
public static Map invert(Map map) {
Map result = instantiate( map.size() );
Iterator iter = map.entrySet().iterator();
while ( iter.hasNext() ) {
Map.Entry me = (Map.Entry) iter.next();
result.put( me.getValue(), me.getKey() );
}
return result;
}
static final class KeyIterator implements Iterator {
private KeyIterator(Iterator iter) {
identityKeyIterator = iter;
}
private final Iterator identityKeyIterator;
public boolean hasNext() {
return identityKeyIterator.hasNext();
}
public Object next() {
return ( (IdentityKey) identityKeyIterator.next() ).key;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}