package jane.core;
import java.util.AbstractCollection;
import java.util.AbstractSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import jane.core.SContext.Rec;
import jane.core.SContext.Safe;
/**
* Map类型的安全修改类
* <p>
* 不支持value为null
*/
public class SMap<K, V, S> implements Map<K, S>, Cloneable
{
public interface SMapListener<K, V>
{
/**
* 增删改统一一个回调接口
* @param rec 对应table及记录键值的封装
* @param changed 所有改动的kv对. 其中value为null的key表示被删除
*/
void onChanged(Rec rec, Map<K, V> changed);
}
protected final Safe<?> _owner;
protected final Map<K, V> _map;
private SContext _sctx;
protected Map<K, V> _changed;
public SMap(Safe<?> owner, Map<K, V> map, final SMapListener<K, V> listener)
{
_owner = owner;
_map = map;
if(listener != null)
{
final Rec rec = owner.record();
if(rec != null)
{
_changed = new HashMap<>();
SContext.current().addOnCommit(new Runnable()
{
@Override
public void run()
{
if(!_changed.isEmpty())
listener.onChanged(rec, _changed);
}
});
}
}
}
protected SMap(Safe<?> owner, Map<K, V> map, Map<K, V> changed)
{
_owner = owner;
_map = map;
_changed = changed;
}
protected SContext sContext()
{
_owner.checkLock();
if(_sctx != null) return _sctx;
_owner.dirty();
return _sctx = SContext.current();
}
@SuppressWarnings("unchecked")
protected S safe(final Object k, final V v)
{
if(!(v instanceof Bean)) return (S)v;
Safe<?> s = ((Bean<?>)v).safe(_owner);
if(_changed != null)
{
s.onDirty(new Runnable()
{
@Override
public void run()
{
_changed.put((K)k, v);
}
});
}
return (S)s;
}
@SuppressWarnings("unchecked")
private S safeAlone(V v)
{
return (S)(v instanceof Bean ? ((Bean<?>)v).safe(null) : v);
}
@SuppressWarnings({ "unchecked", "deprecation" })
private V unsafe(Object v)
{
return (V)(v instanceof Safe ? ((Safe<?>)v).unsafe() : v);
}
protected void addUndoPut(SContext ctx, final K k, final V vOld)
{
ctx.addOnRollback(new Runnable()
{
@Override
public void run()
{
if(vOld != null)
_map.put(k, vOld);
else
_map.remove(k);
}
});
}
protected void addUndoRemove(SContext ctx, final K k, final V vOld)
{
if(_changed != null) _changed.put(k, null);
ctx.addOnRollback(new Runnable()
{
@Override
public void run()
{
_map.put(k, vOld);
}
});
}
@Override
public int size()
{
return _map.size();
}
@Override
public boolean isEmpty()
{
return _map.isEmpty();
}
@SuppressWarnings("unlikely-arg-type")
@Override
public boolean containsKey(Object k)
{
return _map.containsKey(unsafe(k));
}
@Override
public boolean containsValue(Object v)
{
return _map.containsValue(unsafe(v));
}
@Deprecated
public V getUnsafe(Object k)
{
return _map.get(k);
}
@Override
public S get(Object k)
{
return safe(k, _map.get(k));
}
public V putDirect(K k, V v)
{
SContext ctx = sContext();
if(v == null) throw new NullPointerException();
if(_changed != null) _changed.put(k, v);
v = _map.put(k, v);
addUndoPut(ctx, k, v);
return v;
}
@Override
public S put(K k, S s)
{
return safeAlone(putDirect(k, unsafe(s)));
}
@Override
public void putAll(Map<? extends K, ? extends S> m)
{
if(_map == m || this == m) return;
for(Entry<? extends K, ? extends S> e : m.entrySet())
{
S s = e.getValue();
V v = unsafe(s);
if(v != null) putDirect(e.getKey(), v);
}
}
public void putAllDirect(Map<? extends K, ? extends V> m)
{
if(_map == m || this == m) return;
for(Entry<? extends K, ? extends V> e : m.entrySet())
{
V v = e.getValue();
if(v != null) putDirect(e.getKey(), v);
}
}
@SuppressWarnings({ "unchecked", "unlikely-arg-type" })
public V removeDirect(Object k)
{
SContext ctx = sContext();
V vOld = _map.remove(unsafe(k));
if(vOld == null) return null;
addUndoRemove(ctx, (K)k, vOld);
return vOld;
}
@Override
public S remove(Object k)
{
return safeAlone(removeDirect(k));
}
@SuppressWarnings("unchecked")
@Override
public void clear()
{
SContext ctx = sContext();
if(_map.isEmpty()) return;
ctx.addOnRollback(new Runnable()
{
private final Map<K, V> _saved;
{
try
{
_saved = _map.getClass().newInstance();
_saved.putAll(_map);
}
catch(Exception e)
{
throw new Error(e);
}
}
@Override
public void run()
{
_map.clear();
_map.putAll(_saved);
_saved.clear();
}
});
if(_changed != null)
{
for(K k : _map.keySet())
_changed.put(k, null);
}
_map.clear();
}
public final class SEntry implements Entry<K, S>
{
private final Entry<K, V> _e;
protected SEntry(Entry<K, V> e)
{
_e = e;
}
@Override
public K getKey()
{
return _e.getKey();
}
@Deprecated
public V getValueUnsafe()
{
return _e.getValue();
}
@Override
public S getValue()
{
return safe(_e.getKey(), _e.getValue());
}
public V setValueDirect(V v)
{
SContext ctx = sContext();
if(v == null) throw new NullPointerException();
K k = _e.getKey();
if(_changed != null) _changed.put(k, v);
v = _e.setValue(v);
addUndoPut(ctx, k, v);
return v;
}
@Override
public S setValue(S s)
{
return safeAlone(setValueDirect(unsafe(s)));
}
@Override
public int hashCode()
{
return _e.hashCode();
}
@Override
public boolean equals(Object o)
{
return this == o || _e.equals(o);
}
}
public abstract class SIterator<E> implements Iterator<E>
{
private final Iterator<Entry<K, V>> _it = _map.entrySet().iterator();
private SEntry _cur;
@Override
public boolean hasNext()
{
return _it.hasNext();
}
public SEntry nextEntry()
{
return _cur = new SEntry(_it.next());
}
@Override
public void remove()
{
SContext ctx = sContext();
K k = _cur.getKey();
V v = _cur.getValueUnsafe();
_it.remove();
addUndoRemove(ctx, k, v);
}
}
public final class SEntrySet extends AbstractSet<Entry<K, S>>
{
private Set<Entry<K, V>> _it;
private SEntrySet()
{
}
@Override
public SIterator<Entry<K, S>> iterator()
{
return new SIterator<Entry<K, S>>()
{
@Override
public SEntry next()
{
return nextEntry();
}
};
}
@Override
public int size()
{
return SMap.this.size();
}
@Override
public boolean contains(Object o)
{
if(_it == null) _it = _map.entrySet();
return _it.contains(unsafe(o));
}
@SuppressWarnings("unchecked")
@Override
public boolean remove(Object o)
{
return o instanceof Entry && SMap.this.remove(((Entry<K, ?>)o).getKey()) != null;
}
@Override
public void clear()
{
SMap.this.clear();
}
}
public final class SKeySet extends AbstractSet<K>
{
private SKeySet()
{
}
@Override
public SIterator<K> iterator()
{
return new SIterator<K>()
{
@Override
public K next()
{
return nextEntry().getKey();
}
};
}
@Override
public int size()
{
return SMap.this.size();
}
@Override
public boolean contains(Object o)
{
return SMap.this.containsKey(o);
}
@Override
public boolean remove(Object o)
{
return SMap.this.remove(o) != null;
}
@Override
public void clear()
{
SMap.this.clear();
}
}
public final class SValues extends AbstractCollection<S>
{
private SValues()
{
}
@Override
public SIterator<S> iterator()
{
return new SIterator<S>()
{
@Override
public S next()
{
return nextEntry().getValue();
}
};
}
@Override
public int size()
{
return SMap.this.size();
}
@Override
public boolean contains(Object o)
{
return SMap.this.containsValue(o);
}
@Override
public void clear()
{
SMap.this.clear();
}
}
@Override
public SEntrySet entrySet()
{
return new SEntrySet();
}
@Override
public SKeySet keySet()
{
return new SKeySet();
}
@Override
public SValues values()
{
return new SValues();
}
public SMap<K, V, S> append(Map<K, V> map)
{
Util.appendDeep(map, _map);
return this;
}
public SMap<K, V, S> assign(Map<K, V> map)
{
clear();
Util.appendDeep(map, _map);
return this;
}
public void appendTo(Map<K, V> map)
{
Util.appendDeep(_map, map);
}
public void cloneTo(Map<K, V> map)
{
map.clear();
Util.appendDeep(_map, map);
}
@SuppressWarnings("unchecked")
@Override
public final Map<K, V> clone()
{
try
{
return Util.appendDeep(_map, _map.getClass().newInstance());
}
catch(Exception e)
{
throw new Error(e);
}
}
@Override
public int hashCode()
{
return _map.hashCode();
}
@Override
public boolean equals(Object o)
{
return this == o || _map.equals(o);
}
@Override
public String toString()
{
return _map.toString();
}
}