net.sf.javagimmicks.collections.mapping.DualMapValueMappings Maven / Gradle / Ivy
package net.sf.javagimmicks.collections.mapping;
import java.io.Serializable;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.Map.Entry;
import net.sf.javagimmicks.collections.event.AbstractEventMap;
public class DualMapValueMappings extends AbstractValueMappings
{
private static final long serialVersionUID = 7852860994833056710L;
public static DualMapValueMappings createHashHashInstance()
{
return new DualMapValueMappings(StoreType.HASH.getFactory(), StoreType.HASH.getFactory());
}
public static DualMapValueMappings createHashTreeInstance()
{
return new DualMapValueMappings(StoreType.HASH.getFactory(), StoreType.TREE.getFactory());
}
public static DualMapValueMappings createTreeHashInstance()
{
return new DualMapValueMappings(StoreType.TREE.getFactory(), StoreType.HASH.getFactory());
}
public static DualMapValueMappings createTreeTreeInstance()
{
return new DualMapValueMappings(StoreType.TREE.getFactory(), StoreType.TREE.getFactory());
}
protected final OuterMap _left;
protected DualMapValueMappings(StoreFactory leftFactory, StoreFactory rightFactory)
{
_left = new OuterMap(leftFactory, rightFactory);
}
@SuppressWarnings("unchecked")
@Override
public E put(L left, R right, E value)
{
if(left == null || right == null)
{
throw new IllegalArgumentException("Neither left nor right value may be null!");
}
InnerMap innerMap = (InnerMap) _left.get(left);
if(innerMap == null)
{
_left.put(left, Collections.singletonMap(right, value));
return null;
}
else
{
return innerMap.put(right, value);
}
}
public Map> getLeftOuterMap()
{
return _left;
}
public Map> getRightOuterMap()
{
return _left._partnerMap;
}
protected static class OuterMap extends AbstractMap> implements Map>, Serializable
{
private static final long serialVersionUID = 3088051603731444631L;
protected final StoreFactory _factory;
protected final Map> _internal;
protected final OuterMap _partnerMap;
protected OuterMap(StoreFactory factory, OuterMap partnerMap)
{
_factory = factory;
_internal = factory.createMap();
_partnerMap = partnerMap;
}
protected OuterMap(StoreFactory leftFactory, StoreFactory rightFactory)
{
_factory = leftFactory;
_internal = leftFactory.createMap();
_partnerMap = new OuterMap(rightFactory, this);
}
@Override
public Set>> entrySet()
{
return new OuterMapEntrySet(this);
}
@Override
public Map put(L key, Map value)
{
if(key == null)
{
throw new IllegalArgumentException("Key mustn't be null!");
}
if(value == null || value.isEmpty())
{
InnerMap innerMap = _internal.remove(key);
if(innerMap == null)
{
return null;
}
final Map result = _partnerMap._factory.createMap();
result.putAll(innerMap.getDecorated());
innerMap.clear();
return result;
}
else
{
if(value.containsKey(null))
{
throw new IllegalArgumentException("The value-set may not contain null!");
}
InnerMap innerMap = _internal.get(key);
final Map result;
if(innerMap == null)
{
result = null;
final Map decorated = _partnerMap._factory.createMap();
innerMap = new InnerMap(decorated, _factory, key, _partnerMap);
_internal.put(key, innerMap);
}
else
{
result = _partnerMap._factory.createMap();
result.putAll(innerMap.getDecorated());
innerMap.clearForReuse();
}
innerMap.putAll(value);
return result;
}
}
@Override
public Map remove(Object key)
{
InnerMap innerMap = _internal.remove(key);
if(innerMap == null)
{
return null;
}
final Map result = _partnerMap._factory.createMap();
result.putAll(innerMap);
innerMap.clear();
return result;
}
@Override
public Map get(Object key)
{
return _internal.get(key);
}
}
protected static class OuterMapEntrySet extends AbstractSet>>
{
private final OuterMap _parentMap;
protected OuterMapEntrySet(OuterMap parentMap)
{
_parentMap = parentMap;
}
@Override
public Iterator>> iterator()
{
return new OuterMapEntrySetIterator(_parentMap, _parentMap._internal.entrySet().iterator());
}
@Override
public int size()
{
return _parentMap._internal.size();
}
}
protected static class OuterMapEntrySetIterator implements Iterator>>
{
private final OuterMap _parentMap;
private final Iterator>> _internalIterator;
private Entry> _last;
protected OuterMapEntrySetIterator(OuterMap parentMap, Iterator>> internalIterator)
{
_parentMap = parentMap;
_internalIterator = internalIterator;
}
public boolean hasNext()
{
return _internalIterator.hasNext();
}
public Entry> next()
{
final Entry> nextEntry = _internalIterator.next();
_last = nextEntry;
return new OuterMapEntry(_parentMap, nextEntry);
}
public void remove()
{
_internalIterator.remove();
final InnerMap innerMap = _last.getValue();
innerMap.clear();
}
}
protected static class OuterMapEntry implements Entry>
{
private final OuterMap _parentMap;
private final Entry> _internalEntry;
protected OuterMapEntry(OuterMap parentMap, Entry> internalEntry)
{
_parentMap = parentMap;
_internalEntry = internalEntry;
}
public L getKey()
{
return _internalEntry.getKey();
}
public Map getValue()
{
return _internalEntry.getValue();
}
public Map setValue(Map value)
{
if(value == null || value.isEmpty())
{
throw new IllegalArgumentException("May not explicitly set null or an empty set as entry value!");
}
final InnerMap innerMap = _internalEntry.getValue();
final Map result = _parentMap._partnerMap._factory.createMap();
result.putAll(innerMap.getDecorated());
innerMap.clearForReuse();
innerMap.putAll(value);
return result;
}
public String toString()
{
return new StringBuilder()
.append(getKey())
.append("=[")
.append(getValue())
.append("]")
.toString();
}
}
protected static class InnerMap extends AbstractEventMap
{
private static final long serialVersionUID = -8381132398717092121L;
protected final StoreFactory _factory;
protected final L _left;
protected final OuterMap _otherMap;
protected boolean _detached = false;
private boolean _internalFlag = false;
protected InnerMap(Map decorated, StoreFactory factory, L left, OuterMap otherMap)
{
super(decorated);
_factory = factory;
_left = left;
_otherMap = otherMap;
}
@Override
public E put(R key, E value)
{
if(_detached)
{
throw new IllegalStateException("Value set is detached! No further adding possible!");
}
return super.put(key, value);
}
protected void clearForReuse()
{
_internalFlag = true;
clear();
_internalFlag = false;
}
@Override
protected void fireEntryAdded(R key, E value)
{
Map> otherInternalMap = _otherMap._internal;
InnerMap otherInnerMap = otherInternalMap.get(key);
if(otherInnerMap == null)
{
Map otherDecoratedMap = _factory.createMap();
otherInnerMap = new InnerMap(otherDecoratedMap, _otherMap._factory, key, _otherMap._partnerMap);
otherInternalMap.put(key, otherInnerMap);
}
otherInnerMap.getDecorated().put(_left, value);
}
@Override
protected void fireEntryRemoved(R key, E value)
{
Map> otherInternalMap = _otherMap._internal;
InnerMap otherInnerMap = otherInternalMap.get(key);
otherInnerMap.getDecorated().remove(_left);
if(otherInnerMap.isEmpty())
{
otherInnerMap._detached = true;
otherInternalMap.remove(key);
}
if(isEmpty() && !_internalFlag)
{
_detached = true;
_otherMap._partnerMap._internal.remove(_left);
}
}
@Override
protected void fireEntryUpdated(R key, E oldValue, E newValue)
{
Map> otherInternalMap = _otherMap._internal;
InnerMap otherInnerMap = otherInternalMap.get(key);
otherInnerMap.getDecorated().put(_left, newValue);
}
}
protected static interface StoreFactory extends Serializable
{
public Map createMap();
}
public static enum StoreType
{
HASH(new StoreFactory()
{
private static final long serialVersionUID = 2570752436161022580L;
public Map createMap() { return new HashMap(); }
}),
TREE(new StoreFactory()
{
private static final long serialVersionUID = -2301586648259664423L;
public Map createMap() { return new TreeMap(); }
});
private final StoreFactory _factory;
StoreType(StoreFactory factory)
{
_factory = factory;
}
public StoreFactory getFactory()
{
return _factory;
}
};
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy