/*
This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option) any
later version.
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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along
with this program; if not, see http://www.gnu.org/licenses or write to the Free
Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
*/
package com.servoy.j2db.util;
import java.io.Serializable;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* Map with alias for some of the key values.
*
* @author rgansevles
*
*/
public class AliasKeyMap<K, A, V> extends AbstractMap<K, V> implements Serializable
{
private final Map<K, V> map;
private Map<A, K> aliases;
private final AliasGetter<A, V> aliasGetter;
public AliasKeyMap(Map<K, V> map, AliasGetter<A, V> aliasGetter)
{
this.map = map;
this.aliasGetter = aliasGetter;
}
public AliasKeyMap(Map<K, V> map)
{
this(map, null);
}
@SuppressWarnings("unchecked")
protected A getAlias(V value)
{
if (aliasGetter != null)
{
return aliasGetter.getAlias(value);
}
if (value instanceof ISupportAlias< ? >)
{
return ((ISupportAlias< ? extends A>)value).getAlias();
}
return null;
}
@Override
public V put(K key, V value)
{
V old = map.put(key, value);
if (old != null) removeAlias(key); // old alias must go away; even if the put value is the same, it's alias might have changed
A alias = getAlias(value);
if (alias != null && !alias.equals(key))
{
if (aliases == null)
{
aliases = new HashMap<A, K>();
}
aliases.put(alias, key);
}
return old;
}
@Override
public V remove(Object key)
{
return super.remove(removeAlias(key));
}
@SuppressWarnings("unchecked")
protected K removeAlias(Object key)
{
if (aliases == null) return (K)key;
if (aliases.containsKey(key))
{
return aliases.remove(key);
}
K realKey = (K)key;
// find mappings to old key
if (realKey != null)
{
Iterator<K> iterator = aliases.values().iterator();
while (iterator.hasNext())
{
if (realKey.equals(iterator.next()))
{
iterator.remove();
break;
}
}
}
return realKey;
}
@Override
public V get(Object key)
{
return map.get((aliases != null && aliases.containsKey(key)) ? aliases.get(key) : key);
}
@Override
public boolean containsKey(Object key)
{
return (aliases != null && aliases.containsKey(key)) || super.containsKey(key);
}
/**
* @param oldKey
*/
public void updateAlias(Object oldKey)
{
K realKey = removeAlias(oldKey);
if (map.containsKey(realKey))
{
A alias = getAlias(map.get(realKey));
if (alias != null && !alias.equals(realKey))
{
if (aliases == null)
{
aliases = new HashMap<A, K>();
}
aliases.put(alias, realKey);
}
}
}
@Override
public void clear()
{
super.clear();
aliases = null;
}
@Override
public Set<java.util.Map.Entry<K, V>> entrySet()
{
return map.entrySet();
}
public static interface ISupportAlias<A>
{
A getAlias();
}
public static interface AliasGetter<A, V> extends Serializable
{
A getAlias(V value);
}
}