@Test public void testMap () { Protocol.Session session = testSession(); TestDB one = new TestDB(), two = new TestDB(); one.maxMap.put("one", 1); one.maxMap.put("two", 2); session.sync(one); session.sync(two); one.maxMap.put("three", 3); one.maxMap.put("four", 4); one.maxMap.remove("one"); two.maxMap.put("four", 44); session.sync(one); session.sync(two); session.sync(one); one.assertEquals(two); assertEquals(ImmutableMap.of("two", 2, "three", 3, "four", 44), two.maxMap); one.assertEquals(one.clone()); assertEquals(0, one.getMods().size()); assertEquals(0, two.getMods().size()); }
protected <K,V> RMap<K,V> map (final String prefix, final Codec<K> keyCodec, final Codec<V> valCodec, final Resolver<? super V> resolver) { class StorageMap extends AbstractMap<K,V> { @Override public int size () { return _keys.size(); } @Override public boolean containsKey (Object key) { return _keys.contains(key); } @Override public V get (Object rawKey) { return valCodec.decode(_storage.getItem(skey(rawKey)), null); } @Override public V put (K key, V value) { _keys.add(key); String skey = skey(key); String valstr = valCodec.encode(value); String ovalstr = _storage.getItem(skey); setItem(skey, valstr); if (!valstr.equals(ovalstr)) noteModified(skey); return valCodec.decode(ovalstr, null); } @Override public V remove (Object rawKey) { String ovalue = _storage.getItem(skey(rawKey)); _keys.remove(rawKey); return valCodec.decode(ovalue, null); } @Override public Set<K> keySet () { return Collections.unmodifiableSet(_keys); } @Override public Set<Map.Entry<K,V>> entrySet () { return new AbstractSet<Map.Entry<K,V>>() { @Override public Iterator<Map.Entry<K,V>> iterator () { return new Iterator<Map.Entry<K,V>>() { public boolean hasNext () { return _keysIter.hasNext(); } public Map.Entry<K,V> next () { final K key = _keysIter.next(); return new Map.Entry<K,V>() { @Override public K getKey () { return key; } @Override public V getValue () { return StorageMap.this.get(key); } @Override public V setValue (V value) { return StorageMap.this.put(key, value); } }; } public void remove () { _keysIter.remove(); } protected Iterator<K> _keysIter = _keys.iterator(); }; } @Override public int size () { return _keys.size(); } }; } protected String skey (Object rawKey) { @SuppressWarnings("unchecked") K key = (K)rawKey; return DBUtil.mapKey(prefix, key, keyCodec); } protected final Set<K> _keys = new HashSet<K>(sget(mapKeysKey(prefix), keyCodec)) { @Override public boolean add (K elem) { if (!_superctordone) return super.add(elem); if (!super.add(elem)) return false; sset(mapKeysKey(prefix), this, keyCodec); return true; } @Override public boolean remove (Object elem) { if (!super.remove(elem)) return false; @SuppressWarnings("unchecked") K key = (K)elem; removeStorage(key); sset(mapKeysKey(prefix), this, keyCodec); return true; } @Override public Iterator<K> iterator () { final Iterator<K> iter = super.iterator(); return new Iterator<K>() { @Override public boolean hasNext () { return iter.hasNext(); } @Override public K next () { return _current = iter.next(); } @Override public void remove () { iter.remove(); removeStorage(_current); } protected K _current; }; } protected void removeStorage (K key) { String skey = skey(key); removeItem(skey); noteModified(skey); } protected boolean _superctordone = true; }; } final RMap<K,V> map = new RMap<K,V>(new StorageMap()); _props.put(prefix, new Property() { public boolean merge (String name, String data) { K skey = keyCodec.decode(name.substring(prefix.length()+1)); if (data == null) { map.remove(skey); return true; } V svalue = valCodec.decode(data), nvalue = resolver.resolve(map.get(skey), svalue); map.put(skey, nvalue); return nvalue.equals(svalue); } public void update (String name, String data) { K skey = keyCodec.decode(name.substring(prefix.length()+1)); if (data == null) map.remove(skey); else map.put(skey, valCodec.decode(data)); } public void prepareToMeld () { for (K key : map.keySet()) noteModified(DBUtil.mapKey(prefix, key, keyCodec)); } }); _props.put(mapKeysKey(prefix), new Property() { public boolean merge (String name, String data) { return true; } public void update (String name, String data) {} public void prepareToMeld () {} }); return map; }
SyncDB { protected <K,V> RMap<K,V> map (final String prefix, final Codec<K> keyCodec, final Codec<V> valCodec, final Resolver<? super V> resolver) { class StorageMap extends AbstractMap<K,V> { @Override public int size () { return _keys.size(); } @Override public boolean containsKey (Object key) { return _keys.contains(key); } @Override public V get (Object rawKey) { return valCodec.decode(_storage.getItem(skey(rawKey)), null); } @Override public V put (K key, V value) { _keys.add(key); String skey = skey(key); String valstr = valCodec.encode(value); String ovalstr = _storage.getItem(skey); setItem(skey, valstr); if (!valstr.equals(ovalstr)) noteModified(skey); return valCodec.decode(ovalstr, null); } @Override public V remove (Object rawKey) { String ovalue = _storage.getItem(skey(rawKey)); _keys.remove(rawKey); return valCodec.decode(ovalue, null); } @Override public Set<K> keySet () { return Collections.unmodifiableSet(_keys); } @Override public Set<Map.Entry<K,V>> entrySet () { return new AbstractSet<Map.Entry<K,V>>() { @Override public Iterator<Map.Entry<K,V>> iterator () { return new Iterator<Map.Entry<K,V>>() { public boolean hasNext () { return _keysIter.hasNext(); } public Map.Entry<K,V> next () { final K key = _keysIter.next(); return new Map.Entry<K,V>() { @Override public K getKey () { return key; } @Override public V getValue () { return StorageMap.this.get(key); } @Override public V setValue (V value) { return StorageMap.this.put(key, value); } }; } public void remove () { _keysIter.remove(); } protected Iterator<K> _keysIter = _keys.iterator(); }; } @Override public int size () { return _keys.size(); } }; } protected String skey (Object rawKey) { @SuppressWarnings("unchecked") K key = (K)rawKey; return DBUtil.mapKey(prefix, key, keyCodec); } protected final Set<K> _keys = new HashSet<K>(sget(mapKeysKey(prefix), keyCodec)) { @Override public boolean add (K elem) { if (!_superctordone) return super.add(elem); if (!super.add(elem)) return false; sset(mapKeysKey(prefix), this, keyCodec); return true; } @Override public boolean remove (Object elem) { if (!super.remove(elem)) return false; @SuppressWarnings("unchecked") K key = (K)elem; removeStorage(key); sset(mapKeysKey(prefix), this, keyCodec); return true; } @Override public Iterator<K> iterator () { final Iterator<K> iter = super.iterator(); return new Iterator<K>() { @Override public boolean hasNext () { return iter.hasNext(); } @Override public K next () { return _current = iter.next(); } @Override public void remove () { iter.remove(); removeStorage(_current); } protected K _current; }; } protected void removeStorage (K key) { String skey = skey(key); removeItem(skey); noteModified(skey); } protected boolean _superctordone = true; }; } final RMap<K,V> map = new RMap<K,V>(new StorageMap()); _props.put(prefix, new Property() { public boolean merge (String name, String data) { K skey = keyCodec.decode(name.substring(prefix.length()+1)); if (data == null) { map.remove(skey); return true; } V svalue = valCodec.decode(data), nvalue = resolver.resolve(map.get(skey), svalue); map.put(skey, nvalue); return nvalue.equals(svalue); } public void update (String name, String data) { K skey = keyCodec.decode(name.substring(prefix.length()+1)); if (data == null) map.remove(skey); else map.put(skey, valCodec.decode(data)); } public void prepareToMeld () { for (K key : map.keySet()) noteModified(DBUtil.mapKey(prefix, key, keyCodec)); } }); _props.put(mapKeysKey(prefix), new Property() { public boolean merge (String name, String data) { return true; } public void update (String name, String data) {} public void prepareToMeld () {} }); return map; } }
SyncDB { protected <K,V> RMap<K,V> map (final String prefix, final Codec<K> keyCodec, final Codec<V> valCodec, final Resolver<? super V> resolver) { class StorageMap extends AbstractMap<K,V> { @Override public int size () { return _keys.size(); } @Override public boolean containsKey (Object key) { return _keys.contains(key); } @Override public V get (Object rawKey) { return valCodec.decode(_storage.getItem(skey(rawKey)), null); } @Override public V put (K key, V value) { _keys.add(key); String skey = skey(key); String valstr = valCodec.encode(value); String ovalstr = _storage.getItem(skey); setItem(skey, valstr); if (!valstr.equals(ovalstr)) noteModified(skey); return valCodec.decode(ovalstr, null); } @Override public V remove (Object rawKey) { String ovalue = _storage.getItem(skey(rawKey)); _keys.remove(rawKey); return valCodec.decode(ovalue, null); } @Override public Set<K> keySet () { return Collections.unmodifiableSet(_keys); } @Override public Set<Map.Entry<K,V>> entrySet () { return new AbstractSet<Map.Entry<K,V>>() { @Override public Iterator<Map.Entry<K,V>> iterator () { return new Iterator<Map.Entry<K,V>>() { public boolean hasNext () { return _keysIter.hasNext(); } public Map.Entry<K,V> next () { final K key = _keysIter.next(); return new Map.Entry<K,V>() { @Override public K getKey () { return key; } @Override public V getValue () { return StorageMap.this.get(key); } @Override public V setValue (V value) { return StorageMap.this.put(key, value); } }; } public void remove () { _keysIter.remove(); } protected Iterator<K> _keysIter = _keys.iterator(); }; } @Override public int size () { return _keys.size(); } }; } protected String skey (Object rawKey) { @SuppressWarnings("unchecked") K key = (K)rawKey; return DBUtil.mapKey(prefix, key, keyCodec); } protected final Set<K> _keys = new HashSet<K>(sget(mapKeysKey(prefix), keyCodec)) { @Override public boolean add (K elem) { if (!_superctordone) return super.add(elem); if (!super.add(elem)) return false; sset(mapKeysKey(prefix), this, keyCodec); return true; } @Override public boolean remove (Object elem) { if (!super.remove(elem)) return false; @SuppressWarnings("unchecked") K key = (K)elem; removeStorage(key); sset(mapKeysKey(prefix), this, keyCodec); return true; } @Override public Iterator<K> iterator () { final Iterator<K> iter = super.iterator(); return new Iterator<K>() { @Override public boolean hasNext () { return iter.hasNext(); } @Override public K next () { return _current = iter.next(); } @Override public void remove () { iter.remove(); removeStorage(_current); } protected K _current; }; } protected void removeStorage (K key) { String skey = skey(key); removeItem(skey); noteModified(skey); } protected boolean _superctordone = true; }; } final RMap<K,V> map = new RMap<K,V>(new StorageMap()); _props.put(prefix, new Property() { public boolean merge (String name, String data) { K skey = keyCodec.decode(name.substring(prefix.length()+1)); if (data == null) { map.remove(skey); return true; } V svalue = valCodec.decode(data), nvalue = resolver.resolve(map.get(skey), svalue); map.put(skey, nvalue); return nvalue.equals(svalue); } public void update (String name, String data) { K skey = keyCodec.decode(name.substring(prefix.length()+1)); if (data == null) map.remove(skey); else map.put(skey, valCodec.decode(data)); } public void prepareToMeld () { for (K key : map.keySet()) noteModified(DBUtil.mapKey(prefix, key, keyCodec)); } }); _props.put(mapKeysKey(prefix), new Property() { public boolean merge (String name, String data) { return true; } public void update (String name, String data) {} public void prepareToMeld () {} }); return map; } protected  SyncDB(Platform platform); }
SyncDB { protected <K,V> RMap<K,V> map (final String prefix, final Codec<K> keyCodec, final Codec<V> valCodec, final Resolver<? super V> resolver) { class StorageMap extends AbstractMap<K,V> { @Override public int size () { return _keys.size(); } @Override public boolean containsKey (Object key) { return _keys.contains(key); } @Override public V get (Object rawKey) { return valCodec.decode(_storage.getItem(skey(rawKey)), null); } @Override public V put (K key, V value) { _keys.add(key); String skey = skey(key); String valstr = valCodec.encode(value); String ovalstr = _storage.getItem(skey); setItem(skey, valstr); if (!valstr.equals(ovalstr)) noteModified(skey); return valCodec.decode(ovalstr, null); } @Override public V remove (Object rawKey) { String ovalue = _storage.getItem(skey(rawKey)); _keys.remove(rawKey); return valCodec.decode(ovalue, null); } @Override public Set<K> keySet () { return Collections.unmodifiableSet(_keys); } @Override public Set<Map.Entry<K,V>> entrySet () { return new AbstractSet<Map.Entry<K,V>>() { @Override public Iterator<Map.Entry<K,V>> iterator () { return new Iterator<Map.Entry<K,V>>() { public boolean hasNext () { return _keysIter.hasNext(); } public Map.Entry<K,V> next () { final K key = _keysIter.next(); return new Map.Entry<K,V>() { @Override public K getKey () { return key; } @Override public V getValue () { return StorageMap.this.get(key); } @Override public V setValue (V value) { return StorageMap.this.put(key, value); } }; } public void remove () { _keysIter.remove(); } protected Iterator<K> _keysIter = _keys.iterator(); }; } @Override public int size () { return _keys.size(); } }; } protected String skey (Object rawKey) { @SuppressWarnings("unchecked") K key = (K)rawKey; return DBUtil.mapKey(prefix, key, keyCodec); } protected final Set<K> _keys = new HashSet<K>(sget(mapKeysKey(prefix), keyCodec)) { @Override public boolean add (K elem) { if (!_superctordone) return super.add(elem); if (!super.add(elem)) return false; sset(mapKeysKey(prefix), this, keyCodec); return true; } @Override public boolean remove (Object elem) { if (!super.remove(elem)) return false; @SuppressWarnings("unchecked") K key = (K)elem; removeStorage(key); sset(mapKeysKey(prefix), this, keyCodec); return true; } @Override public Iterator<K> iterator () { final Iterator<K> iter = super.iterator(); return new Iterator<K>() { @Override public boolean hasNext () { return iter.hasNext(); } @Override public K next () { return _current = iter.next(); } @Override public void remove () { iter.remove(); removeStorage(_current); } protected K _current; }; } protected void removeStorage (K key) { String skey = skey(key); removeItem(skey); noteModified(skey); } protected boolean _superctordone = true; }; } final RMap<K,V> map = new RMap<K,V>(new StorageMap()); _props.put(prefix, new Property() { public boolean merge (String name, String data) { K skey = keyCodec.decode(name.substring(prefix.length()+1)); if (data == null) { map.remove(skey); return true; } V svalue = valCodec.decode(data), nvalue = resolver.resolve(map.get(skey), svalue); map.put(skey, nvalue); return nvalue.equals(svalue); } public void update (String name, String data) { K skey = keyCodec.decode(name.substring(prefix.length()+1)); if (data == null) map.remove(skey); else map.put(skey, valCodec.decode(data)); } public void prepareToMeld () { for (K key : map.keySet()) noteModified(DBUtil.mapKey(prefix, key, keyCodec)); } }); _props.put(mapKeysKey(prefix), new Property() { public boolean merge (String name, String data) { return true; } public void update (String name, String data) {} public void prepareToMeld () {} }); return map; } protected  SyncDB(Platform platform); int version(); boolean hasUnsyncedChanges(); Map<String,String> getDelta(); Map<String,Integer> getMods(); void noteSync(int version, Map<String,Integer> syncedMods); boolean containsMerges(Map<String,String> delta); void applyDelta(int version, Map<String,String> delta); void prepareToMeld(); void processPurges(); }
SyncDB { protected <K,V> RMap<K,V> map (final String prefix, final Codec<K> keyCodec, final Codec<V> valCodec, final Resolver<? super V> resolver) { class StorageMap extends AbstractMap<K,V> { @Override public int size () { return _keys.size(); } @Override public boolean containsKey (Object key) { return _keys.contains(key); } @Override public V get (Object rawKey) { return valCodec.decode(_storage.getItem(skey(rawKey)), null); } @Override public V put (K key, V value) { _keys.add(key); String skey = skey(key); String valstr = valCodec.encode(value); String ovalstr = _storage.getItem(skey); setItem(skey, valstr); if (!valstr.equals(ovalstr)) noteModified(skey); return valCodec.decode(ovalstr, null); } @Override public V remove (Object rawKey) { String ovalue = _storage.getItem(skey(rawKey)); _keys.remove(rawKey); return valCodec.decode(ovalue, null); } @Override public Set<K> keySet () { return Collections.unmodifiableSet(_keys); } @Override public Set<Map.Entry<K,V>> entrySet () { return new AbstractSet<Map.Entry<K,V>>() { @Override public Iterator<Map.Entry<K,V>> iterator () { return new Iterator<Map.Entry<K,V>>() { public boolean hasNext () { return _keysIter.hasNext(); } public Map.Entry<K,V> next () { final K key = _keysIter.next(); return new Map.Entry<K,V>() { @Override public K getKey () { return key; } @Override public V getValue () { return StorageMap.this.get(key); } @Override public V setValue (V value) { return StorageMap.this.put(key, value); } }; } public void remove () { _keysIter.remove(); } protected Iterator<K> _keysIter = _keys.iterator(); }; } @Override public int size () { return _keys.size(); } }; } protected String skey (Object rawKey) { @SuppressWarnings("unchecked") K key = (K)rawKey; return DBUtil.mapKey(prefix, key, keyCodec); } protected final Set<K> _keys = new HashSet<K>(sget(mapKeysKey(prefix), keyCodec)) { @Override public boolean add (K elem) { if (!_superctordone) return super.add(elem); if (!super.add(elem)) return false; sset(mapKeysKey(prefix), this, keyCodec); return true; } @Override public boolean remove (Object elem) { if (!super.remove(elem)) return false; @SuppressWarnings("unchecked") K key = (K)elem; removeStorage(key); sset(mapKeysKey(prefix), this, keyCodec); return true; } @Override public Iterator<K> iterator () { final Iterator<K> iter = super.iterator(); return new Iterator<K>() { @Override public boolean hasNext () { return iter.hasNext(); } @Override public K next () { return _current = iter.next(); } @Override public void remove () { iter.remove(); removeStorage(_current); } protected K _current; }; } protected void removeStorage (K key) { String skey = skey(key); removeItem(skey); noteModified(skey); } protected boolean _superctordone = true; }; } final RMap<K,V> map = new RMap<K,V>(new StorageMap()); _props.put(prefix, new Property() { public boolean merge (String name, String data) { K skey = keyCodec.decode(name.substring(prefix.length()+1)); if (data == null) { map.remove(skey); return true; } V svalue = valCodec.decode(data), nvalue = resolver.resolve(map.get(skey), svalue); map.put(skey, nvalue); return nvalue.equals(svalue); } public void update (String name, String data) { K skey = keyCodec.decode(name.substring(prefix.length()+1)); if (data == null) map.remove(skey); else map.put(skey, valCodec.decode(data)); } public void prepareToMeld () { for (K key : map.keySet()) noteModified(DBUtil.mapKey(prefix, key, keyCodec)); } }); _props.put(mapKeysKey(prefix), new Property() { public boolean merge (String name, String data) { return true; } public void update (String name, String data) {} public void prepareToMeld () {} }); return map; } protected  SyncDB(Platform platform); int version(); boolean hasUnsyncedChanges(); Map<String,String> getDelta(); Map<String,Integer> getMods(); void noteSync(int version, Map<String,Integer> syncedMods); boolean containsMerges(Map<String,String> delta); void applyDelta(int version, Map<String,String> delta); void prepareToMeld(); void processPurges();  }