Internal entities

This commit is contained in:
Magnus Ulf Jørgensen 2017-04-19 21:37:10 +02:00
parent fe81648eb7
commit 5c416c3a1d
16 changed files with 1178 additions and 723 deletions

View File

@ -3,6 +3,7 @@ package com.massivecraft.massivecore;
import com.massivecraft.massivecore.adapter.AdapterBackstringSet; import com.massivecraft.massivecore.adapter.AdapterBackstringSet;
import com.massivecraft.massivecore.adapter.AdapterBannerPatterns; import com.massivecraft.massivecore.adapter.AdapterBannerPatterns;
import com.massivecraft.massivecore.adapter.AdapterEntry; import com.massivecraft.massivecore.adapter.AdapterEntry;
import com.massivecraft.massivecore.adapter.AdapterEntityInternalMap;
import com.massivecraft.massivecore.adapter.AdapterInventory; import com.massivecraft.massivecore.adapter.AdapterInventory;
import com.massivecraft.massivecore.adapter.AdapterItemStack; import com.massivecraft.massivecore.adapter.AdapterItemStack;
import com.massivecraft.massivecore.adapter.AdapterJsonElement; import com.massivecraft.massivecore.adapter.AdapterJsonElement;
@ -38,6 +39,7 @@ import com.massivecraft.massivecore.nms.NmsItemStackCreate17R4P;
import com.massivecraft.massivecore.ps.PS; import com.massivecraft.massivecore.ps.PS;
import com.massivecraft.massivecore.ps.PSAdapter; import com.massivecraft.massivecore.ps.PSAdapter;
import com.massivecraft.massivecore.store.Coll; import com.massivecraft.massivecore.store.Coll;
import com.massivecraft.massivecore.store.EntityInternalMap;
import com.massivecraft.massivecore.store.ModificationPollerLocal; import com.massivecraft.massivecore.store.ModificationPollerLocal;
import com.massivecraft.massivecore.store.ModificationPollerRemote; import com.massivecraft.massivecore.store.ModificationPollerRemote;
import com.massivecraft.massivecore.util.BoardUtil; import com.massivecraft.massivecore.util.BoardUtil;
@ -165,6 +167,9 @@ public class MassiveCore extends MassivePlugin
ret.registerTypeAdapter(Inventory.class, AdapterInventory.get()); ret.registerTypeAdapter(Inventory.class, AdapterInventory.get());
ret.registerTypeAdapter(PlayerInventory.class, AdapterPlayerInventory.get()); ret.registerTypeAdapter(PlayerInventory.class, AdapterPlayerInventory.get());
// Storage
ret.registerTypeAdapter(EntityInternalMap.class, AdapterEntityInternalMap.get());
// Return // Return
return ret; return ret;
} }

View File

@ -0,0 +1,70 @@
package com.massivecraft.massivecore.adapter;
import com.massivecraft.massivecore.store.EntityInternal;
import com.massivecraft.massivecore.store.EntityInternalMap;
import com.massivecraft.massivecore.xlib.gson.*;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Map.Entry;
public class AdapterEntityInternalMap implements JsonDeserializer<EntityInternalMap<?>>, JsonSerializer<EntityInternalMap<?>>
{
// -------------------------------------------- //
// INSTANCE & CONSTRUCT
// -------------------------------------------- //
private static final AdapterEntityInternalMap i = new AdapterEntityInternalMap();
public static AdapterEntityInternalMap get() { return i; }
// -------------------------------------------- //
// OVERRIDE
// -------------------------------------------- //
@Override
public JsonElement serialize(EntityInternalMap<?> src, Type type, JsonSerializationContext context)
{
// NULL
if (src == null) return JsonNull.INSTANCE;
// Get value
Map<String, ?> contents = src.getIdToEntity();
// Create ret
JsonElement ret = context.serialize(contents);
// Return Ret
return ret;
}
@Override
public EntityInternalMap<?> deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException
{
// NULL
if (json == null) return null;
if (json instanceof JsonNull) return null;
// Get type
Class<? extends EntityInternal> entityType = (Class) ((ParameterizedType) type).getActualTypeArguments()[0];
// Create ret
EntityInternalMap ret = new EntityInternalMap<>(entityType);
// Fill ret
JsonObject jsonObject = (JsonObject) json;
for (Entry<String, JsonElement> entry : jsonObject.entrySet())
{
String id = entry.getKey();
JsonElement value = entry.getValue();
EntityInternal obj = context.deserialize(value, entityType);
ret.getIdToEntityRaw().put(id, obj);
}
// Return ret
return ret;
}
}

View File

@ -3,12 +3,9 @@ package com.massivecraft.massivecore.store;
import com.massivecraft.massivecore.MassiveCore; import com.massivecraft.massivecore.MassiveCore;
import com.massivecraft.massivecore.MassiveCoreMConf; import com.massivecraft.massivecore.MassiveCoreMConf;
import com.massivecraft.massivecore.MassivePlugin; import com.massivecraft.massivecore.MassivePlugin;
import com.massivecraft.massivecore.Named;
import com.massivecraft.massivecore.collections.MassiveList; import com.massivecraft.massivecore.collections.MassiveList;
import com.massivecraft.massivecore.comparator.ComparatorNaturalOrder; import com.massivecraft.massivecore.comparator.ComparatorNaturalOrder;
import com.massivecraft.massivecore.mixin.MixinModification; import com.massivecraft.massivecore.mixin.MixinModification;
import com.massivecraft.massivecore.predicate.Predicate;
import com.massivecraft.massivecore.predicate.PredicateEqualsIgnoreCase;
import com.massivecraft.massivecore.store.migrator.MigratorUtil; import com.massivecraft.massivecore.store.migrator.MigratorUtil;
import com.massivecraft.massivecore.util.ReflectionUtil; import com.massivecraft.massivecore.util.ReflectionUtil;
import com.massivecraft.massivecore.util.Txt; import com.massivecraft.massivecore.util.Txt;
@ -131,249 +128,20 @@ public class Coll<E extends Entity<E>> extends CollAbstract<E>
// -------------------------------------------- // // -------------------------------------------- //
// Loaded // Loaded
protected Map<String, E> id2entity; protected Map<String, E> idToEntity;
@Override @Override public Map<String, E> getIdToEntityRaw() { return this.idToEntity; }
public String fixId(Object oid)
{
if (oid == null) return null;
String ret = null;
if (oid instanceof String) ret = (String) oid;
else if (oid.getClass() == this.getEntityClass()) ret = ((Entity<?>) oid).getId();
if (ret == null) return null;
return this.isLowercasing() ? ret.toLowerCase() : ret;
}
@Override public Map<String, E> getId2entity() { return Collections.unmodifiableMap(this.id2entity); }
@Override
public E getFixed(String id, boolean creative)
{
return this.getFixed(id, creative, true);
}
protected E getFixed(String id, boolean creative, boolean noteModification)
{
if (id == null) return null;
E ret = this.id2entity.get(id);
if (ret != null) return ret;
if ( ! creative) return null;
return this.create(id, noteModification);
}
@Override public Collection<String> getIds() { return Collections.unmodifiableCollection(this.id2entity.keySet()); }
@Override public Collection<String> getIdsRemote() { return this.getDb().getIds(this); } @Override public Collection<String> getIdsRemote() { return this.getDb().getIds(this); }
@Override
public boolean containsIdFixed(String id)
{
if (id == null) return false;
return this.id2entity.containsKey(id);
}
@Override
public boolean containsEntity(Object entity)
{
return this.id2entity.containsValue(entity);
}
@Override public Collection<E> getAll()
{
return Collections.unmodifiableCollection(this.id2entity.values());
}
// -------------------------------------------- // // -------------------------------------------- //
// BEHAVIOR // BEHAVIOR
// -------------------------------------------- // // -------------------------------------------- //
protected boolean creative;
@Override public boolean isCreative() { return this.creative; }
@Override public void setCreative(boolean creative) { this.creative = creative; }
// "Lowercasing" means that the ids are always converted to lower case when fixed.
// This is highly recommended for sender colls.
// The senderIds are case insensitive by nature and some times you simply can't know the correct casing.
protected boolean lowercasing;
@Override public boolean isLowercasing() { return this.lowercasing; }
@Override public void setLowercasing(boolean lowercasing) { this.lowercasing = lowercasing; }
// Should that instance be saved or not?
// If it is default it should not be saved.
@Override
public boolean isDefault(E entity)
{
return entity.isDefault();
}
// What entity version do we want? // What entity version do we want?
protected final int entityTargetVersion; protected final int entityTargetVersion;
@Override public int getEntityTargetVersion() { return this.entityTargetVersion; } @Override public int getEntityTargetVersion() { return this.entityTargetVersion; }
// -------------------------------------------- //
// COPY AND CREATE
// -------------------------------------------- //
@Override
public void copy(E efrom, E eto)
{
if (efrom == null) throw new NullPointerException("efrom");
if (eto == null) throw new NullPointerException("eto");
eto.load(efrom);
}
// This simply creates and returns a new instance
// It does not detach/attach or anything. Just creates a new instance.
@Override
public E createNewInstance()
{
try
{
return this.getEntityClass().newInstance();
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
// Create new instance with the requested id
@Override
public synchronized E create(Object oid)
{
return this.create(oid, true);
}
public synchronized E create(Object oid, boolean noteModification)
{
E entity = this.createNewInstance();
if (this.attach(entity, oid, noteModification) == null) return null;
return entity;
}
// -------------------------------------------- //
// ATTACH AND DETACH
// -------------------------------------------- //
@Override
public String attach(E entity, Object oid)
{
return this.attach(entity, oid, true);
}
protected synchronized String attach(E entity, Object oid, boolean noteModification)
{
// Check entity
if (entity == null) return null;
if (entity.attached()) return entity.getId();
String id;
// Check/Fix id
if (oid == null)
{
id = MStore.createId();
}
else
{
id = this.fixId(oid);
if (id == null) return null;
if (this.id2entity.containsKey(id)) return null;
}
// PRE
this.preAttach(entity, id);
// Add entity reference info
entity.setColl(this);
entity.setId(id);
// Attach
this.id2entity.put(id, entity);
// Identify Modification
if (noteModification)
{
this.identifiedModifications.put(id, Modification.LOCAL_ATTACH);
}
// POST
this.postAttach(entity, id);
return id;
}
@Override
public E detachEntity(E entity)
{
if (entity == null) throw new NullPointerException("entity");
String id = entity.getId();
if (id == null)
{
// It seems the entity is already detached.
// In such case just silently return it.
return entity;
}
this.detachFixed(entity, id);
return entity;
}
@Override
public E detachIdFixed(String id)
{
if (id == null) throw new NullPointerException("id");
E e = this.get(id, false);
if (e == null) return null;
this.detachFixed(e, id);
return e;
}
private void detachFixed(E entity, String id)
{
if (entity == null) throw new NullPointerException("entity");
if (id == null) throw new NullPointerException("id");
// PRE
this.preDetach(entity, id);
// Remove @ local
this.removeAtLocalFixed(id);
// Identify Modification
this.identifiedModifications.put(id, Modification.LOCAL_DETACH);
// POST
this.postDetach(entity, id);
}
@Override
public void preAttach(E entity, String id)
{
entity.preAttach(id);
}
@Override
public void postAttach(E entity, String id)
{
entity.postAttach(id);
}
@Override
public void preDetach(E entity, String id)
{
entity.preDetach(id);
}
@Override
public void postDetach(E entity, String id)
{
entity.postDetach(id);
}
// -------------------------------------------- // // -------------------------------------------- //
// IDENTIFIED MODIFICATIONS // IDENTIFIED MODIFICATIONS
// -------------------------------------------- // // -------------------------------------------- //
@ -438,12 +206,12 @@ public class Coll<E extends Entity<E>> extends CollAbstract<E>
this.removeIdentifiedModificationFixed(id); this.removeIdentifiedModificationFixed(id);
E entity = this.id2entity.remove(id); E entity = this.idToEntity.remove(id);
if (entity == null) return null; if (entity == null) return null;
entity.clearSyncLogFields(); entity.clearSyncLogFields();
// Remove entity reference info // Remove entity reference info
entity.setColl(null); entity.setContainer(null);
entity.setId(null); entity.setId(null);
return entity; return entity;
@ -467,7 +235,7 @@ public class Coll<E extends Entity<E>> extends CollAbstract<E>
this.removeIdentifiedModificationFixed(id); this.removeIdentifiedModificationFixed(id);
E entity = this.id2entity.get(id); E entity = this.idToEntity.get(id);
if (entity == null) return; if (entity == null) return;
entity.clearSyncLogFields(); entity.clearSyncLogFields();
@ -623,7 +391,7 @@ public class Coll<E extends Entity<E>> extends CollAbstract<E>
// } // }
if (current != null && current.hasTopPriority()) return current; if (current != null && current.hasTopPriority()) return current;
E localEntity = this.id2entity.get(id); E localEntity = this.idToEntity.get(id);
if (remoteMtime == null && remote) if (remoteMtime == null && remote)
{ {
// TODO: This is slow // TODO: This is slow
@ -713,7 +481,7 @@ public class Coll<E extends Entity<E>> extends CollAbstract<E>
Modification actualModification = this.examineIdFixed(id, remoteMtime, true, true); Modification actualModification = this.examineIdFixed(id, remoteMtime, true, true);
if (MassiveCoreMConf.get().warnOnLocalAlter && modification == Modification.UNKNOWN_LOG && actualModification.isModified()) if (MassiveCoreMConf.get().warnOnLocalAlter && modification == Modification.UNKNOWN_LOG && actualModification.isModified())
{ {
E entity = this.id2entity.get(id); E entity = this.idToEntity.get(id);
if (entity != null) if (entity != null)
{ {
this.logModification(entity, actualModification); this.logModification(entity, actualModification);
@ -831,10 +599,10 @@ public class Coll<E extends Entity<E>> extends CollAbstract<E>
Map<String, Long> id2RemoteMtime = this.getDb().getId2mtime(this); Map<String, Long> id2RemoteMtime = this.getDb().getId2mtime(this);
// Java 8 // Java 8
//this.id2entity.keySet().forEach(id -> id2RemoteMtime.putIfAbsent(id, 0)); //this.idToEntity.keySet().forEach(id -> id2RemoteMtime.putIfAbsent(id, 0));
// Java 8 > // Java 8 >
for (String id : this.id2entity.keySet()) for (String id : this.idToEntity.keySet())
{ {
if (id2RemoteMtime.containsKey(id)) continue; if (id2RemoteMtime.containsKey(id)) continue;
id2RemoteMtime.put(id, 0L); id2RemoteMtime.put(id, 0L);
@ -859,7 +627,7 @@ public class Coll<E extends Entity<E>> extends CollAbstract<E>
@Override @Override
public void identifyLocalModifications(Modification veto) public void identifyLocalModifications(Modification veto)
{ {
for (String id : id2entity.keySet()) for (String id : idToEntity.keySet())
{ {
this.identifyLocalModificationFixed(id, veto); this.identifyLocalModificationFixed(id, veto);
} }
@ -883,10 +651,10 @@ public class Coll<E extends Entity<E>> extends CollAbstract<E>
//Note: We must also check local ids, in case of remote detach. //Note: We must also check local ids, in case of remote detach.
// Java 8 // Java 8
//this.id2entity.keySet().forEach(id -> id2RemoteMtime.putIfAbsent(id, 0)); //this.idToEntity.keySet().forEach(id -> id2RemoteMtime.putIfAbsent(id, 0));
// Java 8 > // Java 8 >
for (String id : this.id2entity.keySet()) for (String id : this.idToEntity.keySet())
{ {
if (id2RemoteMtime.containsKey(id)) continue; if (id2RemoteMtime.containsKey(id)) continue;
id2RemoteMtime.put(id, 0L); id2RemoteMtime.put(id, 0L);
@ -996,7 +764,7 @@ public class Coll<E extends Entity<E>> extends CollAbstract<E>
this.collDriverObject = db.createCollDriverObject(this); this.collDriverObject = db.createCollDriverObject(this);
// Collections // Collections
this.id2entity = new ConcurrentHashMap<>(); this.idToEntity = new ConcurrentHashMap<>();
this.identifiedModifications = new ConcurrentHashMap<>(); this.identifiedModifications = new ConcurrentHashMap<>();
// Migration // Migration
@ -1075,6 +843,12 @@ public class Coll<E extends Entity<E>> extends CollAbstract<E>
return MStore.getDb(); return MStore.getDb();
} }
@Override
public Coll<E> getColl()
{
return this;
}
// -------------------------------------------- // // -------------------------------------------- //
// ACTIVE // ACTIVE
// -------------------------------------------- // // -------------------------------------------- //
@ -1085,6 +859,8 @@ public class Coll<E extends Entity<E>> extends CollAbstract<E>
return name2instance.containsKey(this.getName()); return name2instance.containsKey(this.getName());
} }
@Override public boolean isLive() { return this.isActive(); }
@Override @Override
public void setActive(boolean active) public void setActive(boolean active)
{ {
@ -1141,31 +917,4 @@ public class Coll<E extends Entity<E>> extends CollAbstract<E>
this.setActive(plugin != null); this.setActive(plugin != null);
} }
// -------------------------------------------- //
// NAME UTILITIES
// -------------------------------------------- //
public E getByName(String name)
{
if (name == null) throw new NullPointerException("name");
Predicate<String> predicate = PredicateEqualsIgnoreCase.get(name);
for (E entity : this.getAll())
{
if (entity == null) continue;
if ( ! (entity instanceof Named)) continue;
Named named = (Named)entity;
if (predicate.apply(named.getName())) return entity;
}
return null;
}
public boolean isNameTaken(String str)
{
return this.getByName(str) != null;
}
} }

View File

@ -1,16 +1,11 @@
package com.massivecraft.massivecore.store; package com.massivecraft.massivecore.store;
import com.massivecraft.massivecore.predicate.Predicate;
import com.massivecraft.massivecore.util.MUtil;
import com.massivecraft.massivecore.xlib.gson.JsonObject; import com.massivecraft.massivecore.xlib.gson.JsonObject;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
public abstract class CollAbstract<E extends Entity<E>> implements CollInterface<E> public abstract class CollAbstract<E extends Entity<E>> extends EntityContainerAbstract<E> implements CollInterface<E>
{ {
// -------------------------------------------- // // -------------------------------------------- //
// WHAT DO WE HANDLE? // WHAT DO WE HANDLE?
@ -22,140 +17,6 @@ public abstract class CollAbstract<E extends Entity<E>> implements CollInterface
return this.getId(); return this.getId();
} }
// -------------------------------------------- //
// SUPPORTING SYSTEM
// -------------------------------------------- //
// This is all placed in the implementation.
// -------------------------------------------- //
// STORAGE
// -------------------------------------------- //
@Override
public String fixIdOrThrow(Object oid) throws IllegalArgumentException
{
String ret = this.fixId(oid);
if (ret == null) throw new IllegalArgumentException(String.valueOf(oid) + " is not a valid id.");
return ret;
}
@Override
public E get(Object oid)
{
return this.getFixed(this.fixId(oid));
}
@Override
public E get(Object oid, boolean creative)
{
return this.getFixed(this.fixId(oid), creative);
}
@Override
public E getFixed(String id)
{
return this.getFixed(id, this.isCreative());
}
@Override
public boolean containsId(Object oid)
{
return this.containsIdFixed(this.fixId(oid));
}
@Override public List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Comparator<? super E> orderby, Integer limit, Integer offset) { return MUtil.transform(this.getAll(oids), where, orderby, limit, offset); }
@Override public List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Comparator<? super E> orderby, Integer limit) { return MUtil.transform(this.getAll(oids), where, orderby, limit); }
@Override public List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Comparator<? super E> orderby) { return MUtil.transform(this.getAll(oids), where, orderby); }
@Override public List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Integer limit, Integer offset) { return MUtil.transform(this.getAll(oids), where, limit, offset); }
@Override public List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Integer limit) { return MUtil.transform(this.getAll(oids), where, limit); }
@Override public List<E> getAll(Iterable<?> oids, Comparator<? super E> orderby, Integer limit, Integer offset) { return MUtil.transform(this.getAll(oids), limit, offset); }
@Override public List<E> getAll(Iterable<?> oids, Comparator<? super E> orderby, Integer limit) { return MUtil.transform(this.getAll(oids), limit); }
@Override public List<E> getAll(Iterable<?> oids, Predicate<? super E> where) { return MUtil.transform(this.getAll(oids), where); }
@Override public List<E> getAll(Iterable<?> oids, Comparator<? super E> orderby) { return MUtil.transform(this.getAll(oids), orderby); }
@Override public List<E> getAll(Iterable<?> oids, Integer limit, Integer offset) { return MUtil.transform(this.getAll(oids), limit, offset); }
@Override public List<E> getAll(Iterable<?> oids, Integer limit) { return MUtil.transform(this.getAll(oids), limit); }
@Override public List<E> getAll(Iterable<?> oids)
{
// Return Create
List<E> ret = new ArrayList<>();
// Return Fill
for (Object oid : oids)
{
E e = this.get(oid);
if (e == null) continue;
ret.add(e);
}
// Return Return
return ret;
}
@Override public List<E> getAll(Predicate<? super E> where, Comparator<? super E> orderby, Integer limit, Integer offset) { return MUtil.transform(this.getAll(), where, orderby, limit, offset); }
@Override public List<E> getAll(Predicate<? super E> where, Comparator<? super E> orderby, Integer limit) { return MUtil.transform(this.getAll(), where, orderby, limit); }
@Override public List<E> getAll(Predicate<? super E> where, Comparator<? super E> orderby) { return MUtil.transform(this.getAll(), where, orderby); }
@Override public List<E> getAll(Predicate<? super E> where, Integer limit, Integer offset) { return MUtil.transform(this.getAll(), where, limit, offset); }
@Override public List<E> getAll(Predicate<? super E> where, Integer limit) { return MUtil.transform(this.getAll(), where, limit); }
@Override public List<E> getAll(Comparator<? super E> orderby, Integer limit, Integer offset) { return MUtil.transform(this.getAll(), limit, offset); }
@Override public List<E> getAll(Comparator<? super E> orderby, Integer limit) { return MUtil.transform(this.getAll(), limit); }
@Override public List<E> getAll(Predicate<? super E> where) { return MUtil.transform(this.getAll(), where); }
@Override public List<E> getAll(Comparator<? super E> orderby) { return MUtil.transform(this.getAll(), orderby); }
@Override public List<E> getAll(Integer limit, Integer offset) { return MUtil.transform(this.getAll(), limit, offset); }
@Override public List<E> getAll(Integer limit) { return MUtil.transform(this.getAll(), limit); }
// -------------------------------------------- //
// BEHAVIOR
// -------------------------------------------- //
// This is all placed in the implementation.
// -------------------------------------------- //
// COPY AND CREATE
// -------------------------------------------- //
// Create new instance with automatic id
@Override
public E create()
{
return this.create(null);
}
// -------------------------------------------- //
// ATTACH AND DETACH
// -------------------------------------------- //
@Override
public String attach(E entity)
{
return this.attach(entity, null);
}
@Override
public E detachId(Object oid)
{
if (oid == null) throw new NullPointerException("oid");
return this.detachIdFixed(this.fixIdOrThrow(oid));
}
// -------------------------------------------- //
// IDENTIFIED MODIFICATIONS
// -------------------------------------------- //
@Override
public void putIdentifiedModification(Object oid, Modification modification)
{
if (oid == null) throw new NullPointerException("oid");
this.putIdentifiedModificationFixed(this.fixIdOrThrow(oid), modification);
}
@Override
public void removeIdentifiedModification(Object oid)
{
if (oid == null) throw new NullPointerException("oid");
this.removeIdentifiedModificationFixed(this.fixIdOrThrow(oid));
}
// -------------------------------------------- // // -------------------------------------------- //
// SYNC LOG // SYNC LOG
// -------------------------------------------- // // -------------------------------------------- //
@ -242,14 +103,4 @@ public abstract class CollAbstract<E extends Entity<E>> implements CollInterface
return this.syncIdFixed(id, modification, null); return this.syncIdFixed(id, modification, null);
} }
// -------------------------------------------- //
// SYNC RUNNABLES / SCHEDULING
// -------------------------------------------- //
// This is all in the implementation
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
// This is all in the implementation;
} }

View File

@ -4,16 +4,13 @@ import com.massivecraft.massivecore.Active;
import com.massivecraft.massivecore.Identified; import com.massivecraft.massivecore.Identified;
import com.massivecraft.massivecore.MassivePlugin; import com.massivecraft.massivecore.MassivePlugin;
import com.massivecraft.massivecore.Named; import com.massivecraft.massivecore.Named;
import com.massivecraft.massivecore.predicate.Predicate;
import com.massivecraft.massivecore.xlib.gson.JsonObject; import com.massivecraft.massivecore.xlib.gson.JsonObject;
import java.util.Collection; import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
public interface CollInterface<E extends Entity<E>> extends Named, Active, Identified public interface CollInterface<E extends Entity<E>> extends Named, Active, Identified, EntityContainer<E>
{ {
// -------------------------------------------- // // -------------------------------------------- //
// WHAT DO WE HANDLE? // WHAT DO WE HANDLE?
@ -42,117 +39,18 @@ public interface CollInterface<E extends Entity<E>> extends Named, Active, Ident
// STORAGE // STORAGE
// -------------------------------------------- // // -------------------------------------------- //
String fixId(Object oid);
String fixIdOrThrow(Object oid) throws IllegalArgumentException;
Map<String, E> getId2entity();
E get(Object oid);
E get(Object oid, boolean creative);
E getFixed(String id);
E getFixed(String id, boolean creative);
Collection<String> getIds();
Collection<String> getIdsRemote(); Collection<String> getIdsRemote();
boolean containsId(Object oid);
boolean containsIdFixed(String id);
boolean containsEntity(Object entity);
Collection<E> getAll();
List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Comparator<? super E> orderby, Integer limit, Integer offset);
List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Comparator<? super E> orderby, Integer limit);
List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Comparator<? super E> orderby);
List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Integer limit, Integer offset);
List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Integer limit);
List<E> getAll(Iterable<?> oids, Comparator<? super E> orderby, Integer limit, Integer offset);
List<E> getAll(Iterable<?> oids, Comparator<? super E> orderby, Integer limit);
List<E> getAll(Iterable<?> oids, Predicate<? super E> where);
List<E> getAll(Iterable<?> oids, Comparator<? super E> orderby);
List<E> getAll(Iterable<?> oids, Integer limit, Integer offset);
List<E> getAll(Iterable<?> oids, Integer limit);
List<E> getAll(Iterable<?> oids);
List<E> getAll(Predicate<? super E> where, Comparator<? super E> orderby, Integer limit, Integer offset);
List<E> getAll(Predicate<? super E> where, Comparator<? super E> orderby, Integer limit);
List<E> getAll(Predicate<? super E> where, Comparator<? super E> orderby);
List<E> getAll(Predicate<? super E> where, Integer limit, Integer offset);
List<E> getAll(Predicate<? super E> where, Integer limit);
List<E> getAll(Comparator<? super E> orderby, Integer limit, Integer offset);
List<E> getAll(Comparator<? super E> orderby, Integer limit);
List<E> getAll(Predicate<? super E> where);
List<E> getAll(Comparator<? super E> orderby);
List<E> getAll(Integer limit, Integer offset);
List<E> getAll(Integer limit);
// -------------------------------------------- // // -------------------------------------------- //
// BEHAVIOR // BEHAVIOR
// -------------------------------------------- // // -------------------------------------------- //
boolean isCreative();
void setCreative(boolean creative);
boolean isLowercasing();
void setLowercasing(boolean lowercasing);
// A default entity will not be saved.
// This is often used together with creative collections to save disc space.
boolean isDefault(E entity);
int getEntityTargetVersion(); int getEntityTargetVersion();
// -------------------------------------------- //
// COPY AND CREATE
// -------------------------------------------- //
void copy(E fromo, E too);
// This simply creates and returns a new instance
// It does not detach/attach or anything. Just creates a new instance.
E createNewInstance();
// Create new instance with automatic id
E create();
// Create new instance with the requested id
E create(Object oid);
// -------------------------------------------- //
// ATTACH AND DETACH
// -------------------------------------------- //
String attach(E entity);
String attach(E entity, Object oid);
E detachEntity(E entity);
E detachId(Object oid);
E detachIdFixed(String id);
void preAttach(E entity, String id);
void postAttach(E entity, String id);
void preDetach(E entity, String id);
void postDetach(E entity, String id);
// -------------------------------------------- //
// IDENTIFIED MODIFICATIONS
// -------------------------------------------- //
void putIdentifiedModification(Object oid, Modification modification);
void putIdentifiedModificationFixed(String id, Modification modification);
void removeIdentifiedModification(Object oid);
void removeIdentifiedModificationFixed(String id);
// -------------------------------------------- // // -------------------------------------------- //
// SYNC LOG // SYNC LOG
// -------------------------------------------- // // -------------------------------------------- //
/*
public Map<L, Long> lastMtime();
public Map<L, Object> lastRaw();
public Set<L> lastDefault();
public void clearSynclog(Object oid);
*/
Map<String, Long> getSyncMap(boolean in); Map<String, Long> getSyncMap(boolean in);
long getSyncCountFixed(String name, boolean in); long getSyncCountFixed(String name, boolean in);
void addSyncCountFixed(String name, boolean in); void addSyncCountFixed(String name, boolean in);
@ -162,13 +60,11 @@ public interface CollInterface<E extends Entity<E>> extends Named, Active, Ident
// -------------------------------------------- // // -------------------------------------------- //
// oid // oid
E removeAtLocal(Object oid);
void removeAtRemote(Object oid); void removeAtRemote(Object oid);
void saveToRemote(Object oid); void saveToRemote(Object oid);
void loadFromRemote(Object oid, Entry<JsonObject, Long> remoteEntry); void loadFromRemote(Object oid, Entry<JsonObject, Long> remoteEntry);
// Fixed id // Fixed id
E removeAtLocalFixed(String id);
void removeAtRemoteFixed(String id); void removeAtRemoteFixed(String id);
void saveToRemoteFixed(String id); void saveToRemoteFixed(String id);
void loadFromRemoteFixed(String id, Entry<JsonObject, Long> remoteEntry); void loadFromRemoteFixed(String id, Entry<JsonObject, Long> remoteEntry);

View File

@ -1,13 +1,7 @@
package com.massivecraft.massivecore.store; package com.massivecraft.massivecore.store;
import com.massivecraft.massivecore.Identified;
import com.massivecraft.massivecore.MassiveCore;
import com.massivecraft.massivecore.store.accessor.Accessor;
import com.massivecraft.massivecore.xlib.gson.Gson;
import com.massivecraft.massivecore.xlib.gson.JsonObject; import com.massivecraft.massivecore.xlib.gson.JsonObject;
import java.util.Objects;
/** /**
* Usage of this class is highly optional. You may persist anything. If you are * Usage of this class is highly optional. You may persist anything. If you are
* creating the class to be persisted yourself, it might be handy to extend this * creating the class to be persisted yourself, it might be handy to extend this
@ -16,23 +10,17 @@ import java.util.Objects;
// Self referencing generic. // Self referencing generic.
// http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ206 // http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ206
public class Entity<E extends Entity<E>> implements Identified public class Entity<E extends Entity<E>> extends EntityInternal<E>
{ {
// -------------------------------------------- // // -------------------------------------------- //
// FIELDS // FIELDS
// -------------------------------------------- // // -------------------------------------------- //
protected transient Coll<E> coll; public Coll<?> getColl() { return (Coll<?>) this.getContainer(); }
protected void setColl(Coll<E> val) { this.coll = val; }
public Coll<E> getColl() { return this.coll; }
protected transient String id;
protected void setId(String id) { this.id = id; }
@Override public String getId() { return this.id; }
public String getUniverse() public String getUniverse()
{ {
Coll<E> coll = this.getColl(); Coll<?> coll = this.getColl();
if (coll == null) return null; if (coll == null) return null;
return coll.getUniverse(); return coll.getUniverse();
@ -62,79 +50,25 @@ public class Entity<E extends Entity<E>> implements Identified
// -------------------------------------------- // // -------------------------------------------- //
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public String attach(Coll<E> coll) public String attach(EntityContainer<E> container)
{ {
return coll.attach((E) this); if (!(container instanceof Coll)) throw new IllegalArgumentException(container.getClass().getName() + " is not a Coll.");
return container.attach((E) this);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public E detach() public E detach()
{ {
Coll<E> coll = this.getColl(); EntityContainer<E> coll = this.getContainer();
if (coll == null) return (E)this; if (coll == null) return (E)this;
return coll.detachEntity((E) this); return coll.detachEntity((E) this);
} }
public boolean attached()
{
return this.getColl() != null && this.getId() != null;
}
public boolean detached()
{
return ! this.attached();
}
public void preAttach(String id)
{
}
public void postAttach(String id)
{
}
public void preDetach(String id)
{
}
public void postDetach(String id)
{
}
// -------------------------------------------- // // -------------------------------------------- //
// SYNC AND IO ACTIONS // SYNC AND IO ACTIONS
// -------------------------------------------- // // -------------------------------------------- //
public boolean isLive()
{
String id = this.getId();
if (id == null) return false;
Coll<E> coll = this.getColl();
if (coll == null) return false;
if ( ! coll.isActive()) return false;
return true;
}
public void changed()
{
if ( ! this.isLive()) return;
//System.out.println(this.getColl().getName() + ": " +this.getId() + " was modified locally");
// UNKNOWN is very unimportant really.
// LOCAL_ATTACH is for example much more important and should not be replaced.
this.getColl().putIdentifiedModificationFixed(this.getId(), Modification.UNKNOWN);
}
public Modification sync() public Modification sync()
{ {
if (!this.isLive()) return Modification.UNKNOWN; if (!this.isLive()) return Modification.UNKNOWN;
@ -155,61 +89,4 @@ public class Entity<E extends Entity<E>> implements Identified
this.getColl().loadFromRemoteFixed(id, null); this.getColl().loadFromRemoteFixed(id, null);
} }
// -------------------------------------------- //
// DERPINGTON
// -------------------------------------------- //
@SuppressWarnings("unchecked")
public E load(E that)
{
Accessor.get(this.getClass()).copy(that, this);
return (E) this;
}
public boolean isDefault()
{
return false;
}
// -------------------------------------------- //
// CONVENIENCE: DATABASE
// -------------------------------------------- //
// GENERIC
public <T> T convertGet(T value, T standard)
{
return value != null ? value : standard;
}
public <T> T convertSet(T value, T standard)
{
this.changed();
return Objects.equals(value, standard) ? null : value;
}
// BOOLEAN
public boolean convertGet(Boolean value)
{
return convertGet(value, false);
}
public Boolean convertSet(Boolean value)
{
return convertSet(value, false);
}
// -------------------------------------------- //
// STANDARDS
// -------------------------------------------- //
@Override
public String toString()
{
Gson gson = MassiveCore.gson;
Coll<E> coll = this.getColl();
if (coll != null) gson = coll.getGson();
return this.getClass().getSimpleName()+gson.toJson(this, this.getClass());
}
} }

View File

@ -0,0 +1,149 @@
package com.massivecraft.massivecore.store;
import com.massivecraft.massivecore.predicate.Predicate;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
// Most base EntityContainer
public interface EntityContainer<E>
{
String attach(E entity);
String attach(E entity, Object oid);
E detachEntity(E entity);
E detachId(Object oid);
E detachIdFixed(String id);
boolean isLive();
Coll<?> getColl();
// -------------------------------------------- //
// WHAT DO WE HANDLE?
// -------------------------------------------- //
Class<E> getEntityClass();
// -------------------------------------------- //
// STORAGE
// -------------------------------------------- //
String fixId(Object oid);
String fixIdOrThrow(Object oid) throws IllegalArgumentException;
Map<String, E> getIdToEntityRaw();
Map<String, E> getIdToEntity();
E get(Object oid);
E get(Object oid, boolean creative);
E getFixed(String id);
E getFixed(String id, boolean creative);
Collection<String> getIds();
boolean containsId(Object oid);
boolean containsIdFixed(String id);
boolean containsEntity(Object entity);
Collection<E> getAll();
List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Comparator<? super E> orderby, Integer limit, Integer offset);
List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Comparator<? super E> orderby, Integer limit);
List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Comparator<? super E> orderby);
List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Integer limit, Integer offset);
List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Integer limit);
List<E> getAll(Iterable<?> oids, Comparator<? super E> orderby, Integer limit, Integer offset);
List<E> getAll(Iterable<?> oids, Comparator<? super E> orderby, Integer limit);
List<E> getAll(Iterable<?> oids, Predicate<? super E> where);
List<E> getAll(Iterable<?> oids, Comparator<? super E> orderby);
List<E> getAll(Iterable<?> oids, Integer limit, Integer offset);
List<E> getAll(Iterable<?> oids, Integer limit);
List<E> getAll(Iterable<?> oids);
List<E> getAll(Predicate<? super E> where, Comparator<? super E> orderby, Integer limit, Integer offset);
List<E> getAll(Predicate<? super E> where, Comparator<? super E> orderby, Integer limit);
List<E> getAll(Predicate<? super E> where, Comparator<? super E> orderby);
List<E> getAll(Predicate<? super E> where, Integer limit, Integer offset);
List<E> getAll(Predicate<? super E> where, Integer limit);
List<E> getAll(Comparator<? super E> orderby, Integer limit, Integer offset);
List<E> getAll(Comparator<? super E> orderby, Integer limit);
List<E> getAll(Predicate<? super E> where);
List<E> getAll(Comparator<? super E> orderby);
List<E> getAll(Integer limit, Integer offset);
List<E> getAll(Integer limit);
// -------------------------------------------- //
// BEHAVIOR
// -------------------------------------------- //
boolean isCreative();
void setCreative(boolean creative);
boolean isLowercasing();
void setLowercasing(boolean lowercasing);
// A default entity will not be saved.
// This is often used together with creative collections to save disc space.
boolean isDefault(E entity);
// -------------------------------------------- //
// COPY AND CREATE
// -------------------------------------------- //
void copy(E fromo, E too);
// This simply creates and returns a new instance
// It does not detach/attach or anything. Just creates a new instance.
E createNewInstance();
// Create new instance with automatic id
E create();
// Create new instance with the requested id
E create(Object oid);
// -------------------------------------------- //
// ATTACH AND DETACH
// -------------------------------------------- //
/*String attach(E entity);
String attach(E entity, Object oid);
E detachEntity(E entity);
E detachId(Object oid);
E detachIdFixed(String id);*/
void preAttach(E entity, String id);
void postAttach(E entity, String id);
void preDetach(E entity, String id);
void postDetach(E entity, String id);
// -------------------------------------------- //
// IDENTIFIED MODIFICATIONS
// -------------------------------------------- //
void putIdentifiedModification(Object oid, Modification modification);
void putIdentifiedModificationFixed(String id, Modification modification);
void removeIdentifiedModification(Object oid);
void removeIdentifiedModificationFixed(String id);
// -------------------------------------------- //
// SYNC LOWLEVEL IO ACTIONS
// -------------------------------------------- //
// oid
E removeAtLocal(Object oid);
// fixed
E removeAtLocalFixed(String id);
// -------------------------------------------- //
// NAME UTILITIES
// -------------------------------------------- //
E getByName(String name);
boolean isNameTaken(String str);
}

View File

@ -0,0 +1,416 @@
package com.massivecraft.massivecore.store;
import com.massivecraft.massivecore.Named;
import com.massivecraft.massivecore.predicate.Predicate;
import com.massivecraft.massivecore.predicate.PredicateEqualsIgnoreCase;
import com.massivecraft.massivecore.util.MUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
// Calls fixId when necessary
public abstract class EntityContainerAbstract<E extends EntityInternal<E>> implements EntityContainer<E>
{
// -------------------------------------------- //
// STORAGE
// -------------------------------------------- //
@Override public Map<String, E> getIdToEntity() { return Collections.unmodifiableMap(this.getIdToEntityRaw()); }
@Override
public String fixId(Object oid)
{
if (oid == null) return null;
String ret = null;
if (oid instanceof String) ret = (String) oid;
else if (oid.getClass() == this.getEntityClass()) ret = ((Entity<?>) oid).getId();
if (ret == null) return null;
return this.isLowercasing() ? ret.toLowerCase() : ret;
}
@Override
public String fixIdOrThrow(Object oid) throws IllegalArgumentException
{
String ret = this.fixId(oid);
if (ret == null) throw new IllegalArgumentException(String.valueOf(oid) + " is not a valid id.");
return ret;
}
@Override
public E get(Object oid)
{
return this.getFixed(this.fixId(oid));
}
@Override
public E get(Object oid, boolean creative)
{
return this.getFixed(this.fixId(oid), creative);
}
@Override
public E getFixed(String id)
{
return this.getFixed(id, this.isCreative());
}
@Override
public E getFixed(String id, boolean creative)
{
return this.getFixed(id, creative, true);
}
protected E getFixed(String id, boolean creative, boolean noteModification)
{
if (id == null) return null;
E ret = this.getIdToEntity().get(id);
if (ret != null) return ret;
if ( ! creative) return null;
return this.create(id, noteModification);
}
@Override public Collection<String> getIds() { return this.getIdToEntity().keySet(); }
@Override
public boolean containsId(Object oid)
{
return this.containsIdFixed(this.fixId(oid));
}
@Override
public boolean containsIdFixed(String id)
{
if (id == null) return false;
return this.getIdToEntity().containsKey(id);
}
@Override
public boolean containsEntity(Object entity)
{
return this.getIdToEntity().containsValue(entity);
}
@Override public Collection<E> getAll()
{
return this.getIdToEntity().values();
}
@Override public List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Comparator<? super E> orderby, Integer limit, Integer offset) { return MUtil.transform(this.getAll(oids), where, orderby, limit, offset); }
@Override public List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Comparator<? super E> orderby, Integer limit) { return MUtil.transform(this.getAll(oids), where, orderby, limit); }
@Override public List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Comparator<? super E> orderby) { return MUtil.transform(this.getAll(oids), where, orderby); }
@Override public List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Integer limit, Integer offset) { return MUtil.transform(this.getAll(oids), where, limit, offset); }
@Override public List<E> getAll(Iterable<?> oids, Predicate<? super E> where, Integer limit) { return MUtil.transform(this.getAll(oids), where, limit); }
@Override public List<E> getAll(Iterable<?> oids, Comparator<? super E> orderby, Integer limit, Integer offset) { return MUtil.transform(this.getAll(oids), limit, offset); }
@Override public List<E> getAll(Iterable<?> oids, Comparator<? super E> orderby, Integer limit) { return MUtil.transform(this.getAll(oids), limit); }
@Override public List<E> getAll(Iterable<?> oids, Predicate<? super E> where) { return MUtil.transform(this.getAll(oids), where); }
@Override public List<E> getAll(Iterable<?> oids, Comparator<? super E> orderby) { return MUtil.transform(this.getAll(oids), orderby); }
@Override public List<E> getAll(Iterable<?> oids, Integer limit, Integer offset) { return MUtil.transform(this.getAll(oids), limit, offset); }
@Override public List<E> getAll(Iterable<?> oids, Integer limit) { return MUtil.transform(this.getAll(oids), limit); }
@Override public List<E> getAll(Iterable<?> oids)
{
// Return Create
List<E> ret = new ArrayList<>();
// Return Fill
for (Object oid : oids)
{
E e = this.get(oid);
if (e == null) continue;
ret.add(e);
}
// Return Return
return ret;
}
@Override public List<E> getAll(Predicate<? super E> where, Comparator<? super E> orderby, Integer limit, Integer offset) { return MUtil.transform(this.getAll(), where, orderby, limit, offset); }
@Override public List<E> getAll(Predicate<? super E> where, Comparator<? super E> orderby, Integer limit) { return MUtil.transform(this.getAll(), where, orderby, limit); }
@Override public List<E> getAll(Predicate<? super E> where, Comparator<? super E> orderby) { return MUtil.transform(this.getAll(), where, orderby); }
@Override public List<E> getAll(Predicate<? super E> where, Integer limit, Integer offset) { return MUtil.transform(this.getAll(), where, limit, offset); }
@Override public List<E> getAll(Predicate<? super E> where, Integer limit) { return MUtil.transform(this.getAll(), where, limit); }
@Override public List<E> getAll(Comparator<? super E> orderby, Integer limit, Integer offset) { return MUtil.transform(this.getAll(), limit, offset); }
@Override public List<E> getAll(Comparator<? super E> orderby, Integer limit) { return MUtil.transform(this.getAll(), limit); }
@Override public List<E> getAll(Predicate<? super E> where) { return MUtil.transform(this.getAll(), where); }
@Override public List<E> getAll(Comparator<? super E> orderby) { return MUtil.transform(this.getAll(), orderby); }
@Override public List<E> getAll(Integer limit, Integer offset) { return MUtil.transform(this.getAll(), limit, offset); }
@Override public List<E> getAll(Integer limit) { return MUtil.transform(this.getAll(), limit); }
// -------------------------------------------- //
// BEHAVIOR
// -------------------------------------------- //
protected boolean creative;
@Override public boolean isCreative() { return this.creative; }
@Override public void setCreative(boolean creative) { this.creative = creative; }
// "Lowercasing" means that the ids are always converted to lower case when fixed.
// This is highly recommended for sender colls.
// The senderIds are case insensitive by nature and some times you simply can't know the correct casing.
protected boolean lowercasing;
@Override public boolean isLowercasing() { return this.lowercasing; }
@Override public void setLowercasing(boolean lowercasing) { this.lowercasing = lowercasing; }
// Should that instance be saved or not?
// If it is default it should not be saved.
@Override
public boolean isDefault(E entity)
{
return entity.isDefault();
}
// -------------------------------------------- //
// COPY AND CREATE
// -------------------------------------------- //
// Create new instance with automatic id
@Override
public E create()
{
return this.create(null);
}
// -------------------------------------------- //
// COPY AND CREATE
// -------------------------------------------- //
@Override
public void copy(E efrom, E eto)
{
if (efrom == null) throw new NullPointerException("efrom");
if (eto == null) throw new NullPointerException("eto");
eto.load(efrom);
}
// This simply creates and returns a new instance
// It does not detach/attach or anything. Just creates a new instance.
@Override
public E createNewInstance()
{
try
{
return this.getEntityClass().newInstance();
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
// Create new instance with the requested id
@Override
public synchronized E create(Object oid)
{
return this.create(oid, true);
}
public synchronized E create(Object oid, boolean noteModification)
{
E entity = this.createNewInstance();
if (this.attach(entity, oid, noteModification) == null) return null;
return entity;
}
// -------------------------------------------- //
// ATTACH AND DETACH
// -------------------------------------------- //
@Override
public String attach(E entity)
{
return this.attach(entity, null);
}
@Override
public String attach(E entity, Object oid)
{
return this.attach(entity, oid, true);
}
protected synchronized String attach(E entity, Object oid, boolean noteModification)
{
// Check entity
if (entity == null) return null;
if (entity.attached()) return entity.getId();
String id;
// Check/Fix id
if (oid == null)
{
id = MStore.createId();
}
else
{
id = this.fixId(oid);
if (id == null) return null;
if (this.getIdToEntity().containsKey(id)) return null;
}
// PRE
this.preAttach(entity, id);
// Add entity reference info
entity.setContainer(this);
entity.setId(id);
// Attach
this.getIdToEntityRaw().put(id, entity);
// Identify Modification
if (noteModification)
{
this.putIdentifiedModificationFixed(id, Modification.LOCAL_ATTACH);
}
// POST
this.postAttach(entity, id);
return id;
}
@Override
public E detachId(Object oid)
{
if (oid == null) throw new NullPointerException("oid");
return this.detachIdFixed(this.fixIdOrThrow(oid));
}
@Override
public E detachEntity(E entity)
{
if (entity == null) throw new NullPointerException("entity");
String id = entity.getId();
if (id == null)
{
// It seems the entity is already detached.
// In such case just silently return it.
return entity;
}
this.detachFixed(entity, id);
return entity;
}
@Override
public E detachIdFixed(String id)
{
if (id == null) throw new NullPointerException("id");
E e = this.get(id, false);
if (e == null) return null;
this.detachFixed(e, id);
return e;
}
protected void detachFixed(E entity, String id)
{
if (entity == null) throw new NullPointerException("entity");
if (id == null) throw new NullPointerException("id");
// PRE
this.preDetach(entity, id);
// Remove @ local
this.removeAtLocalFixed(id);
// Identify Modification
this.putIdentifiedModificationFixed(id, Modification.LOCAL_DETACH);
// POST
this.postDetach(entity, id);
}
@Override
public void preAttach(E entity, String id)
{
entity.preAttach(id);
}
@Override
public void postAttach(E entity, String id)
{
entity.postAttach(id);
}
@Override
public void preDetach(E entity, String id)
{
entity.preDetach(id);
}
@Override
public void postDetach(E entity, String id)
{
entity.postDetach(id);
}
// -------------------------------------------- //
// IDENTIFIED MODIFICATIONS
// -------------------------------------------- //
@Override
public void putIdentifiedModification(Object oid, Modification modification)
{
if (oid == null) throw new NullPointerException("oid");
this.putIdentifiedModificationFixed(this.fixIdOrThrow(oid), modification);
}
@Override
public void removeIdentifiedModification(Object oid)
{
if (oid == null) throw new NullPointerException("oid");
this.removeIdentifiedModificationFixed(this.fixIdOrThrow(oid));
}
// -------------------------------------------- //
// SYNC LOWLEVEL IO ACTIONS
// -------------------------------------------- //
@Override
public E removeAtLocal(Object oid)
{
if (oid == null) throw new NullPointerException("oid");
return this.removeAtLocalFixed(this.fixIdOrThrow(oid));
}
// -------------------------------------------- //
// NAME UTILITIES
// -------------------------------------------- //
@Override
public E getByName(String name)
{
if (name == null) throw new NullPointerException("name");
Predicate<String> predicate = PredicateEqualsIgnoreCase.get(name);
for (E entity : this.getAll())
{
if (entity == null) continue;
if ( ! (entity instanceof Named)) continue;
Named named = (Named)entity;
if (predicate.apply(named.getName())) return entity;
}
return null;
}
@Override
public boolean isNameTaken(String str)
{
return this.getByName(str) != null;
}
}

View File

@ -0,0 +1,159 @@
package com.massivecraft.massivecore.store;
import com.massivecraft.massivecore.MassiveCore;
import com.massivecraft.massivecore.store.accessor.Accessor;
import com.massivecraft.massivecore.xlib.gson.Gson;
import java.lang.ref.WeakReference;
import java.util.Objects;
public class EntityInternal<E extends EntityInternal<E>>
{
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
protected transient WeakReference<EntityContainer<E>> container = new WeakReference<>(null);
protected void setContainer(EntityContainer<E> container)
{
this.container = new WeakReference<>(container);
}
public EntityContainer<E> getContainer()
{
return this.container.get();
}
public Coll<?> getColl()
{
return this.getContainer().getColl();
}
protected transient String id;
protected void setId(String id)
{
this.id = id;
}
public String getId()
{
return this.id;
}
// -------------------------------------------- //
// ATTACH AND DETACH
// -------------------------------------------- //
public boolean attached()
{
return this.getContainer() != null && this.getId() != null;
}
public boolean detached()
{
return !this.attached();
}
public void preAttach(String id)
{
}
public void postAttach(String id)
{
}
public void preDetach(String id)
{
}
public void postDetach(String id)
{
}
// -------------------------------------------- //
// SYNC AND IO ACTIONS
// -------------------------------------------- //
public boolean isLive()
{
String id = this.getId();
if (id == null) return false;
EntityContainer<E> container = this.getContainer();
if (container == null) return false;
if (!container.isLive()) return false;
return true;
}
public void changed()
{
if (!this.isLive()) return;
//System.out.println(this.getColl().getName() + ": " +this.getId() + " was modified locally");
this.getContainer().putIdentifiedModificationFixed(this.getId(), Modification.UNKNOWN);
}
// -------------------------------------------- //
// DERPINGTON
// -------------------------------------------- //
@SuppressWarnings("unchecked")
public E load(E that)
{
Objects.requireNonNull(that, "that");
Accessor.get(this.getClass()).copy(that, this);
return (E) this;
}
public boolean isDefault()
{
return false;
}
// -------------------------------------------- //
// CONVENIENCE: DATABASE
// -------------------------------------------- //
// GENERIC
public <T> T convertGet(T value, T standard)
{
return value != null ? value : standard;
}
public <T> T convertSet(T value, T standard)
{
this.changed();
return Objects.equals(value, standard) ? null : value;
}
// BOOLEAN
public boolean convertGet(Boolean value)
{
return convertGet(value, false);
}
public Boolean convertSet(Boolean value)
{
return convertSet(value, false);
}
// -------------------------------------------- //
// STANDARDS
// -------------------------------------------- //
@Override
public String toString()
{
Gson gson = MassiveCore.gson;
Coll<?> coll = this.getColl();
if (coll != null) gson = coll.getGson();
return this.getClass().getSimpleName() + gson.toJson(this, this.getClass());
}
}

View File

@ -0,0 +1,228 @@
package com.massivecraft.massivecore.store;
import com.massivecraft.massivecore.collections.MassiveSet;
import java.lang.ref.WeakReference;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class EntityInternalMap<E extends EntityInternal<E>> extends EntityContainerAbstract<E>
{
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
private EntityInternalMap()
{
this.entityClass = null;
}
public EntityInternalMap(Class<E> entityClass)
{
this.entityClass = entityClass;
}
public EntityInternalMap(EntityInternal<?> entity, Class<E> entityClass)
{
Objects.requireNonNull(entity, "entity");
Objects.requireNonNull(entityClass, "entityClass");
this.setEntity(entity);
this.entityClass = entityClass;
}
// -------------------------------------------- //
// REFERENCE
// -------------------------------------------- //
protected transient WeakReference<EntityInternal<?>> entity = new WeakReference<>(null);
protected void setEntity(EntityInternal<?> entity) { this.entity = new WeakReference<EntityInternal<?>>(entity); }
public EntityInternal<?> getEntity() { return this.entity.get(); }
@Override
public boolean isLive()
{
EntityInternal<?> entity = this.getEntity();
if (entity == null) return false;
if (!entity.isLive()) return false;
return true;
}
// -------------------------------------------- //
// WHAT DO WE HANDLE?
// -------------------------------------------- //
protected final transient Class<E> entityClass;
@Override public Class<E> getEntityClass() { return this.entityClass; }
// -------------------------------------------- //
// STORAGE
// -------------------------------------------- //
private final ConcurrentHashMap<String, E> id2Entity = new ConcurrentHashMap<>();
@Override public Map<String, E> getIdToEntityRaw() { return this.id2Entity; }
// -------------------------------------------- //
// REFERENCE
// -------------------------------------------- //
@Override
public Coll<?> getColl()
{
return this.getEntity().getContainer().getColl();
}
// -------------------------------------------- //
// LOAD
// -------------------------------------------- //
public EntityInternalMap<E> load(EntityInternalMap<E> that)
{
Objects.requireNonNull(that, "that");
// Loop over all the entities in that
for (Entry<String, E> entry : that.id2Entity.entrySet())
{
String id = entry.getKey();
E entity = entry.getValue();
E current = this.id2Entity.get(id);
if (current != null)
{
// Load if present
current.load(entity);
}
else
{
// attach if not present
this.attach(entity, id);
}
}
// Clean entities of those that are not in that
if (this.id2Entity.size() != that.id2Entity.size())
{
// Avoid CME
Set<Entry<String, E>> removals = new MassiveSet<>();
// Loop over all current entries ...
for (Iterator<Entry<String, E>> it = this.id2Entity.entrySet().iterator(); it.hasNext(); )
{
Entry<String, E> entry = it.next();
String id = entry.getKey();
// ... if it is not present in those ...
if (that.id2Entity.containsKey(id)) continue;
// ... remove.
removals.add(entry);
}
// Remove
for (Entry<String, E> removal : removals)
{
this.detachFixed(removal.getValue(), removal.getKey());
}
}
return this;
}
// -------------------------------------------- //
// IDENTIFIED MODIFICATIONS
// -------------------------------------------- //
protected Map<String, Modification> identifiedModifications;
@Override
public synchronized void putIdentifiedModificationFixed(String id, Modification modification)
{
Objects.requireNonNull(id, "id");
this.changed();
}
@Override
public synchronized void removeIdentifiedModificationFixed(String id)
{
Objects.requireNonNull(id, "id");
this.changed();
}
private void changed()
{
if (!this.isLive()) return;
//System.out.println(this.getColl().getName() + ": " +this.getId() + " was modified locally");
this.getEntity().changed();
}
// -------------------------------------------- //
// SYNC LOWLEVEL IO ACTIONS
// -------------------------------------------- //
@Override
public synchronized E removeAtLocalFixed(String id)
{
Objects.requireNonNull(id, "id");
this.removeIdentifiedModificationFixed(id);
E entity = this.getIdToEntity().remove(id);
if (entity == null) return null;
// Remove entity reference info
entity.setContainer(null);
entity.setId(null);
return entity;
}
// -------------------------------------------- //
// MAP DELEGATION
// -------------------------------------------- //
public Set<Entry<String, E>> entrySet()
{
return this.getIdToEntityRaw().entrySet();
}
public Set<String> keySet()
{
return this.getIdToEntity().keySet();
}
public boolean containsKey(String id)
{
Objects.requireNonNull(id, "id");
return this.getIdToEntityRaw().containsKey(id);
}
public E remove(String id)
{
Objects.requireNonNull(id, "id");
return this.getIdToEntityRaw().remove(id);
}
public int size()
{
return this.getIdToEntityRaw().size();
}
public boolean isEmpty()
{
return this.getIdToEntityRaw().isEmpty();
}
public void clear()
{
this.getIdToEntityRaw().clear();
}
}

View File

@ -1,5 +1,7 @@
package com.massivecraft.massivecore.store.accessor; package com.massivecraft.massivecore.store.accessor;
import com.massivecraft.massivecore.store.EntityInternalMap;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
@ -72,11 +74,23 @@ public class Accessor
{ {
String fieldName = entry.getKey(); String fieldName = entry.getKey();
Field field = entry.getValue(); Field field = entry.getValue();
FieldAccessor fieldAccessor = new FieldAccessor(field); FieldAccessor fieldAccessor = createFieldAccessor(field);
this.setFieldAccessor(fieldName, fieldAccessor); this.setFieldAccessor(fieldName, fieldAccessor);
} }
} }
public static FieldAccessor createFieldAccessor(Field field)
{
if (EntityInternalMap.class.isAssignableFrom(field.getType()))
{
return new FieldAccessorInternalEntityMap(field);
}
else
{
return new FieldAccessorSimple(field);
}
}
// -------------------------------------------- // // -------------------------------------------- //
// GET & SET & COPY // GET & SET & COPY
// -------------------------------------------- // // -------------------------------------------- //

View File

@ -1,54 +1,8 @@
package com.massivecraft.massivecore.store.accessor; package com.massivecraft.massivecore.store.accessor;
import com.massivecraft.massivecore.util.ReflectionUtil; public interface FieldAccessor
import java.lang.reflect.Field;
public class FieldAccessor
{ {
// -------------------------------------------- // public Object get(Object entity);
// FIELDS public void set(Object entity, Object val);
// -------------------------------------------- //
private final Field field;
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public FieldAccessor(Field field)
{
ReflectionUtil.makeAccessible(field);
this.field = field;
}
// -------------------------------------------- //
// CORE
// -------------------------------------------- //
public Object get(Object entity)
{
try
{
return this.field.get(entity);
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
public void set(Object entity, Object val)
{
try
{
this.field.set(entity, val);
}
catch (Exception e)
{
e.printStackTrace();
}
}
} }

View File

@ -0,0 +1,31 @@
package com.massivecraft.massivecore.store.accessor;
import com.massivecraft.massivecore.store.EntityInternalMap;
import java.lang.reflect.Field;
public class FieldAccessorInternalEntityMap extends FieldAccessorSimple
{
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public FieldAccessorInternalEntityMap(Field field)
{
super(field);
}
// -------------------------------------------- //
// CORE
// -------------------------------------------- //
@SuppressWarnings("unchecked")
public void set(Object entity, Object val)
{
EntityInternalMap entityMap = (EntityInternalMap) this.get(entity);
EntityInternalMap that = (EntityInternalMap) val;
entityMap.load(that);
}
}

View File

@ -0,0 +1,56 @@
package com.massivecraft.massivecore.store.accessor;
import com.massivecraft.massivecore.util.ReflectionUtil;
import java.lang.reflect.Field;
public class FieldAccessorSimple implements FieldAccessor
{
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
private final Field field;
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public FieldAccessorSimple(Field field)
{
ReflectionUtil.makeAccessible(field);
this.field = field;
}
// -------------------------------------------- //
// CORE
// -------------------------------------------- //
public Object get(Object entity)
{
if (!field.getDeclaringClass().isAssignableFrom(entity.getClass())) throw new IllegalArgumentException(field.getDeclaringClass() + " : " + entity.getClass());
try
{
return this.field.get(entity);
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
public void set(Object entity, Object val)
{
try
{
this.field.set(entity, val);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}