From 5c416c3a1d241e3e9adf94c66c9812cb5a639eff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20Ulf=20J=C3=B8rgensen?= Date: Wed, 19 Apr 2017 21:37:10 +0200 Subject: [PATCH] Internal entities --- .../massivecraft/massivecore/MassiveCore.java | 5 + .../adapter/AdapterEntityInternalMap.java | 70 +++ .../massivecore/command/MassiveCommand.java | 18 +- .../massivecraft/massivecore/store/Coll.java | 295 +------------ .../massivecore/store/CollAbstract.java | 151 +------ .../massivecore/store/CollInterface.java | 106 +---- .../massivecore/store/Entity.java | 147 +------ .../massivecore/store/EntityContainer.java | 149 +++++++ .../store/EntityContainerAbstract.java | 416 ++++++++++++++++++ .../massivecore/store/EntityInternal.java | 159 +++++++ .../massivecore/store/EntityInternalMap.java | 228 ++++++++++ .../massivecore/store/accessor/Accessor.java | 16 +- .../store/accessor/FieldAccessor.java | 52 +-- .../FieldAccessorInternalEntityMap.java | 31 ++ .../store/accessor/FieldAccessorSimple.java | 56 +++ .../store/migrator/MigratorFieldConvert.java | 2 +- 16 files changed, 1178 insertions(+), 723 deletions(-) create mode 100644 src/com/massivecraft/massivecore/adapter/AdapterEntityInternalMap.java create mode 100644 src/com/massivecraft/massivecore/store/EntityContainer.java create mode 100644 src/com/massivecraft/massivecore/store/EntityContainerAbstract.java create mode 100644 src/com/massivecraft/massivecore/store/EntityInternal.java create mode 100644 src/com/massivecraft/massivecore/store/EntityInternalMap.java create mode 100644 src/com/massivecraft/massivecore/store/accessor/FieldAccessorInternalEntityMap.java create mode 100644 src/com/massivecraft/massivecore/store/accessor/FieldAccessorSimple.java diff --git a/src/com/massivecraft/massivecore/MassiveCore.java b/src/com/massivecraft/massivecore/MassiveCore.java index fdff1225..6f78dd59 100644 --- a/src/com/massivecraft/massivecore/MassiveCore.java +++ b/src/com/massivecraft/massivecore/MassiveCore.java @@ -3,6 +3,7 @@ package com.massivecraft.massivecore; import com.massivecraft.massivecore.adapter.AdapterBackstringSet; import com.massivecraft.massivecore.adapter.AdapterBannerPatterns; import com.massivecraft.massivecore.adapter.AdapterEntry; +import com.massivecraft.massivecore.adapter.AdapterEntityInternalMap; import com.massivecraft.massivecore.adapter.AdapterInventory; import com.massivecraft.massivecore.adapter.AdapterItemStack; 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.PSAdapter; import com.massivecraft.massivecore.store.Coll; +import com.massivecraft.massivecore.store.EntityInternalMap; import com.massivecraft.massivecore.store.ModificationPollerLocal; import com.massivecraft.massivecore.store.ModificationPollerRemote; import com.massivecraft.massivecore.util.BoardUtil; @@ -165,6 +167,9 @@ public class MassiveCore extends MassivePlugin ret.registerTypeAdapter(Inventory.class, AdapterInventory.get()); ret.registerTypeAdapter(PlayerInventory.class, AdapterPlayerInventory.get()); + // Storage + ret.registerTypeAdapter(EntityInternalMap.class, AdapterEntityInternalMap.get()); + // Return return ret; } diff --git a/src/com/massivecraft/massivecore/adapter/AdapterEntityInternalMap.java b/src/com/massivecraft/massivecore/adapter/AdapterEntityInternalMap.java new file mode 100644 index 00000000..793d66fd --- /dev/null +++ b/src/com/massivecraft/massivecore/adapter/AdapterEntityInternalMap.java @@ -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>, JsonSerializer> +{ + // -------------------------------------------- // + // 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 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 entityType = (Class) ((ParameterizedType) type).getActualTypeArguments()[0]; + + // Create ret + EntityInternalMap ret = new EntityInternalMap<>(entityType); + + // Fill ret + JsonObject jsonObject = (JsonObject) json; + for (Entry 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; + } + +} diff --git a/src/com/massivecraft/massivecore/command/MassiveCommand.java b/src/com/massivecraft/massivecore/command/MassiveCommand.java index de1947f1..4ead2324 100644 --- a/src/com/massivecraft/massivecore/command/MassiveCommand.java +++ b/src/com/massivecraft/massivecore/command/MassiveCommand.java @@ -854,17 +854,17 @@ public class MassiveCommand implements Active, PluginIdentifiableCommand } public void setDescPermission(String descPermission) { this.descPermission = descPermission; } - public String getDescPermission() - { - if (this.descPermission != null) return this.descPermission; - // Otherwise we try to find one. - for (Requirement requirement : this.getRequirements()) + public String getDescPermission() { - if ( ! (requirement instanceof RequirementHasPerm)) continue; - return ((RequirementHasPerm)requirement).getPermissionId(); + if (this.descPermission != null) return this.descPermission; + // Otherwise we try to find one. + for (Requirement requirement : this.getRequirements()) + { + if ( ! (requirement instanceof RequirementHasPerm)) continue; + return ((RequirementHasPerm)requirement).getPermissionId(); + } + return null; } - return null; - } public void setHelp(List val) { this.help = val; } public void setHelp(Object... val) { this.help = Arrays.asList(val); } diff --git a/src/com/massivecraft/massivecore/store/Coll.java b/src/com/massivecraft/massivecore/store/Coll.java index 6b475dd9..a6ef5cb0 100644 --- a/src/com/massivecraft/massivecore/store/Coll.java +++ b/src/com/massivecraft/massivecore/store/Coll.java @@ -3,12 +3,9 @@ package com.massivecraft.massivecore.store; import com.massivecraft.massivecore.MassiveCore; import com.massivecraft.massivecore.MassiveCoreMConf; import com.massivecraft.massivecore.MassivePlugin; -import com.massivecraft.massivecore.Named; import com.massivecraft.massivecore.collections.MassiveList; import com.massivecraft.massivecore.comparator.ComparatorNaturalOrder; 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.util.ReflectionUtil; import com.massivecraft.massivecore.util.Txt; @@ -131,248 +128,19 @@ public class Coll> extends CollAbstract // -------------------------------------------- // // Loaded - protected Map id2entity; + protected Map idToEntity; - @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 Map getIdToEntityRaw() { return this.idToEntity; } - @Override public Map 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 getIds() { return Collections.unmodifiableCollection(this.id2entity.keySet()); } @Override public Collection 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 getAll() - { - return Collections.unmodifiableCollection(this.id2entity.values()); - } // -------------------------------------------- // // 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? protected final int 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 @@ -438,12 +206,12 @@ public class Coll> extends CollAbstract this.removeIdentifiedModificationFixed(id); - E entity = this.id2entity.remove(id); + E entity = this.idToEntity.remove(id); if (entity == null) return null; entity.clearSyncLogFields(); // Remove entity reference info - entity.setColl(null); + entity.setContainer(null); entity.setId(null); return entity; @@ -467,7 +235,7 @@ public class Coll> extends CollAbstract this.removeIdentifiedModificationFixed(id); - E entity = this.id2entity.get(id); + E entity = this.idToEntity.get(id); if (entity == null) return; entity.clearSyncLogFields(); @@ -623,7 +391,7 @@ public class Coll> extends CollAbstract // } if (current != null && current.hasTopPriority()) return current; - E localEntity = this.id2entity.get(id); + E localEntity = this.idToEntity.get(id); if (remoteMtime == null && remote) { // TODO: This is slow @@ -713,7 +481,7 @@ public class Coll> extends CollAbstract Modification actualModification = this.examineIdFixed(id, remoteMtime, true, true); 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) { this.logModification(entity, actualModification); @@ -831,10 +599,10 @@ public class Coll> extends CollAbstract Map id2RemoteMtime = this.getDb().getId2mtime(this); // Java 8 - //this.id2entity.keySet().forEach(id -> id2RemoteMtime.putIfAbsent(id, 0)); + //this.idToEntity.keySet().forEach(id -> id2RemoteMtime.putIfAbsent(id, 0)); // Java 8 > - for (String id : this.id2entity.keySet()) + for (String id : this.idToEntity.keySet()) { if (id2RemoteMtime.containsKey(id)) continue; id2RemoteMtime.put(id, 0L); @@ -859,7 +627,7 @@ public class Coll> extends CollAbstract @Override public void identifyLocalModifications(Modification veto) { - for (String id : id2entity.keySet()) + for (String id : idToEntity.keySet()) { this.identifyLocalModificationFixed(id, veto); } @@ -883,10 +651,10 @@ public class Coll> extends CollAbstract //Note: We must also check local ids, in case of remote detach. // Java 8 - //this.id2entity.keySet().forEach(id -> id2RemoteMtime.putIfAbsent(id, 0)); + //this.idToEntity.keySet().forEach(id -> id2RemoteMtime.putIfAbsent(id, 0)); // Java 8 > - for (String id : this.id2entity.keySet()) + for (String id : this.idToEntity.keySet()) { if (id2RemoteMtime.containsKey(id)) continue; id2RemoteMtime.put(id, 0L); @@ -996,7 +764,7 @@ public class Coll> extends CollAbstract this.collDriverObject = db.createCollDriverObject(this); // Collections - this.id2entity = new ConcurrentHashMap<>(); + this.idToEntity = new ConcurrentHashMap<>(); this.identifiedModifications = new ConcurrentHashMap<>(); // Migration @@ -1075,6 +843,12 @@ public class Coll> extends CollAbstract return MStore.getDb(); } + @Override + public Coll getColl() + { + return this; + } + // -------------------------------------------- // // ACTIVE // -------------------------------------------- // @@ -1085,6 +859,8 @@ public class Coll> extends CollAbstract return name2instance.containsKey(this.getName()); } + @Override public boolean isLive() { return this.isActive(); } + @Override public void setActive(boolean active) { @@ -1140,32 +916,5 @@ public class Coll> extends CollAbstract this.setActivePlugin(plugin); this.setActive(plugin != null); } - - // -------------------------------------------- // - // NAME UTILITIES - // -------------------------------------------- // - - public E getByName(String name) - { - if (name == null) throw new NullPointerException("name"); - - Predicate 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; - } - + } diff --git a/src/com/massivecraft/massivecore/store/CollAbstract.java b/src/com/massivecraft/massivecore/store/CollAbstract.java index f3b5afbe..caa7daba 100644 --- a/src/com/massivecraft/massivecore/store/CollAbstract.java +++ b/src/com/massivecraft/massivecore/store/CollAbstract.java @@ -1,16 +1,11 @@ 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 java.util.ArrayList; -import java.util.Comparator; -import java.util.List; import java.util.Map.Entry; -public abstract class CollAbstract> implements CollInterface +public abstract class CollAbstract> extends EntityContainerAbstract implements CollInterface { // -------------------------------------------- // // WHAT DO WE HANDLE? @@ -21,141 +16,7 @@ public abstract class CollAbstract> implements CollInterface { 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 getAll(Iterable oids, Predicate where, Comparator orderby, Integer limit, Integer offset) { return MUtil.transform(this.getAll(oids), where, orderby, limit, offset); } - @Override public List getAll(Iterable oids, Predicate where, Comparator orderby, Integer limit) { return MUtil.transform(this.getAll(oids), where, orderby, limit); } - @Override public List getAll(Iterable oids, Predicate where, Comparator orderby) { return MUtil.transform(this.getAll(oids), where, orderby); } - @Override public List getAll(Iterable oids, Predicate where, Integer limit, Integer offset) { return MUtil.transform(this.getAll(oids), where, limit, offset); } - @Override public List getAll(Iterable oids, Predicate where, Integer limit) { return MUtil.transform(this.getAll(oids), where, limit); } - @Override public List getAll(Iterable oids, Comparator orderby, Integer limit, Integer offset) { return MUtil.transform(this.getAll(oids), limit, offset); } - @Override public List getAll(Iterable oids, Comparator orderby, Integer limit) { return MUtil.transform(this.getAll(oids), limit); } - @Override public List getAll(Iterable oids, Predicate where) { return MUtil.transform(this.getAll(oids), where); } - @Override public List getAll(Iterable oids, Comparator orderby) { return MUtil.transform(this.getAll(oids), orderby); } - @Override public List getAll(Iterable oids, Integer limit, Integer offset) { return MUtil.transform(this.getAll(oids), limit, offset); } - @Override public List getAll(Iterable oids, Integer limit) { return MUtil.transform(this.getAll(oids), limit); } - - @Override public List getAll(Iterable oids) - { - // Return Create - List 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 getAll(Predicate where, Comparator orderby, Integer limit, Integer offset) { return MUtil.transform(this.getAll(), where, orderby, limit, offset); } - @Override public List getAll(Predicate where, Comparator orderby, Integer limit) { return MUtil.transform(this.getAll(), where, orderby, limit); } - @Override public List getAll(Predicate where, Comparator orderby) { return MUtil.transform(this.getAll(), where, orderby); } - @Override public List getAll(Predicate where, Integer limit, Integer offset) { return MUtil.transform(this.getAll(), where, limit, offset); } - @Override public List getAll(Predicate where, Integer limit) { return MUtil.transform(this.getAll(), where, limit); } - @Override public List getAll(Comparator orderby, Integer limit, Integer offset) { return MUtil.transform(this.getAll(), limit, offset); } - @Override public List getAll(Comparator orderby, Integer limit) { return MUtil.transform(this.getAll(), limit); } - @Override public List getAll(Predicate where) { return MUtil.transform(this.getAll(), where); } - @Override public List getAll(Comparator orderby) { return MUtil.transform(this.getAll(), orderby); } - @Override public List getAll(Integer limit, Integer offset) { return MUtil.transform(this.getAll(), limit, offset); } - @Override public List 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 // -------------------------------------------- // @@ -242,14 +103,4 @@ public abstract class CollAbstract> implements CollInterface return this.syncIdFixed(id, modification, null); } - // -------------------------------------------- // - // SYNC RUNNABLES / SCHEDULING - // -------------------------------------------- // - // This is all in the implementation - - // -------------------------------------------- // - // CONSTRUCT - // -------------------------------------------- // - // This is all in the implementation; - } diff --git a/src/com/massivecraft/massivecore/store/CollInterface.java b/src/com/massivecraft/massivecore/store/CollInterface.java index b8b87809..efad2284 100644 --- a/src/com/massivecraft/massivecore/store/CollInterface.java +++ b/src/com/massivecraft/massivecore/store/CollInterface.java @@ -4,16 +4,13 @@ import com.massivecraft.massivecore.Active; import com.massivecraft.massivecore.Identified; import com.massivecraft.massivecore.MassivePlugin; import com.massivecraft.massivecore.Named; -import com.massivecraft.massivecore.predicate.Predicate; import com.massivecraft.massivecore.xlib.gson.JsonObject; import java.util.Collection; -import java.util.Comparator; -import java.util.List; import java.util.Map; import java.util.Map.Entry; -public interface CollInterface> extends Named, Active, Identified +public interface CollInterface> extends Named, Active, Identified, EntityContainer { // -------------------------------------------- // // WHAT DO WE HANDLE? @@ -42,117 +39,18 @@ public interface CollInterface> extends Named, Active, Ident // STORAGE // -------------------------------------------- // - String fixId(Object oid); - String fixIdOrThrow(Object oid) throws IllegalArgumentException; - - Map getId2entity(); - E get(Object oid); - E get(Object oid, boolean creative); - E getFixed(String id); - E getFixed(String id, boolean creative); - Collection getIds(); Collection getIdsRemote(); - boolean containsId(Object oid); - boolean containsIdFixed(String id); - - boolean containsEntity(Object entity); - - Collection getAll(); - - List getAll(Iterable oids, Predicate where, Comparator orderby, Integer limit, Integer offset); - List getAll(Iterable oids, Predicate where, Comparator orderby, Integer limit); - List getAll(Iterable oids, Predicate where, Comparator orderby); - List getAll(Iterable oids, Predicate where, Integer limit, Integer offset); - List getAll(Iterable oids, Predicate where, Integer limit); - List getAll(Iterable oids, Comparator orderby, Integer limit, Integer offset); - List getAll(Iterable oids, Comparator orderby, Integer limit); - List getAll(Iterable oids, Predicate where); - List getAll(Iterable oids, Comparator orderby); - List getAll(Iterable oids, Integer limit, Integer offset); - List getAll(Iterable oids, Integer limit); - List getAll(Iterable oids); - - List getAll(Predicate where, Comparator orderby, Integer limit, Integer offset); - List getAll(Predicate where, Comparator orderby, Integer limit); - List getAll(Predicate where, Comparator orderby); - List getAll(Predicate where, Integer limit, Integer offset); - List getAll(Predicate where, Integer limit); - List getAll(Comparator orderby, Integer limit, Integer offset); - List getAll(Comparator orderby, Integer limit); - List getAll(Predicate where); - List getAll(Comparator orderby); - List getAll(Integer limit, Integer offset); - List 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); 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 // -------------------------------------------- // - /* - public Map lastMtime(); - public Map lastRaw(); - public Set lastDefault(); - public void clearSynclog(Object oid); - */ - Map getSyncMap(boolean in); long getSyncCountFixed(String name, boolean in); void addSyncCountFixed(String name, boolean in); @@ -162,13 +60,11 @@ public interface CollInterface> extends Named, Active, Ident // -------------------------------------------- // // oid - E removeAtLocal(Object oid); void removeAtRemote(Object oid); void saveToRemote(Object oid); void loadFromRemote(Object oid, Entry remoteEntry); // Fixed id - E removeAtLocalFixed(String id); void removeAtRemoteFixed(String id); void saveToRemoteFixed(String id); void loadFromRemoteFixed(String id, Entry remoteEntry); diff --git a/src/com/massivecraft/massivecore/store/Entity.java b/src/com/massivecraft/massivecore/store/Entity.java index 65bd8964..2bab9ca0 100644 --- a/src/com/massivecraft/massivecore/store/Entity.java +++ b/src/com/massivecraft/massivecore/store/Entity.java @@ -1,13 +1,7 @@ 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 java.util.Objects; - /** * 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 @@ -16,23 +10,17 @@ import java.util.Objects; // Self referencing generic. // http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ206 -public class Entity> implements Identified +public class Entity> extends EntityInternal { // -------------------------------------------- // // FIELDS // -------------------------------------------- // - protected transient Coll coll; - protected void setColl(Coll val) { this.coll = val; } - public Coll getColl() { return this.coll; } - - protected transient String id; - protected void setId(String id) { this.id = id; } - @Override public String getId() { return this.id; } + public Coll getColl() { return (Coll) this.getContainer(); } public String getUniverse() { - Coll coll = this.getColl(); + Coll coll = this.getColl(); if (coll == null) return null; return coll.getUniverse(); @@ -56,160 +44,49 @@ public class Entity> implements Identified this.lastMtime = 0; this.lastDefault = false; } - + // -------------------------------------------- // // ATTACH AND DETACH // -------------------------------------------- // @SuppressWarnings("unchecked") - public String attach(Coll coll) + public String attach(EntityContainer 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") public E detach() { - Coll coll = this.getColl(); + EntityContainer coll = this.getContainer(); if (coll == null) return (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 // -------------------------------------------- // - public boolean isLive() - { - String id = this.getId(); - if (id == null) return false; - - Coll 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() { - if ( ! this.isLive()) return Modification.UNKNOWN; + if (!this.isLive()) return Modification.UNKNOWN; return this.getColl().syncIdFixed(id); } public void saveToRemote() { - if ( ! this.isLive()) return; + if (!this.isLive()) return; this.getColl().saveToRemoteFixed(id); } public void loadFromRemote() { - if ( ! this.isLive()) return; + if (!this.isLive()) return; 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 convertGet(T value, T standard) - { - return value != null ? value : standard; - } - - public 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()); - } - } diff --git a/src/com/massivecraft/massivecore/store/EntityContainer.java b/src/com/massivecraft/massivecore/store/EntityContainer.java new file mode 100644 index 00000000..2f898c15 --- /dev/null +++ b/src/com/massivecraft/massivecore/store/EntityContainer.java @@ -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 +{ + 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 getEntityClass(); + + // -------------------------------------------- // + // STORAGE + // -------------------------------------------- // + + String fixId(Object oid); + String fixIdOrThrow(Object oid) throws IllegalArgumentException; + + Map getIdToEntityRaw(); + Map getIdToEntity(); + E get(Object oid); + E get(Object oid, boolean creative); + E getFixed(String id); + E getFixed(String id, boolean creative); + Collection getIds(); + boolean containsId(Object oid); + boolean containsIdFixed(String id); + + boolean containsEntity(Object entity); + + Collection getAll(); + + List getAll(Iterable oids, Predicate where, Comparator orderby, Integer limit, Integer offset); + List getAll(Iterable oids, Predicate where, Comparator orderby, Integer limit); + List getAll(Iterable oids, Predicate where, Comparator orderby); + List getAll(Iterable oids, Predicate where, Integer limit, Integer offset); + List getAll(Iterable oids, Predicate where, Integer limit); + List getAll(Iterable oids, Comparator orderby, Integer limit, Integer offset); + List getAll(Iterable oids, Comparator orderby, Integer limit); + List getAll(Iterable oids, Predicate where); + List getAll(Iterable oids, Comparator orderby); + List getAll(Iterable oids, Integer limit, Integer offset); + List getAll(Iterable oids, Integer limit); + List getAll(Iterable oids); + + List getAll(Predicate where, Comparator orderby, Integer limit, Integer offset); + List getAll(Predicate where, Comparator orderby, Integer limit); + List getAll(Predicate where, Comparator orderby); + List getAll(Predicate where, Integer limit, Integer offset); + List getAll(Predicate where, Integer limit); + List getAll(Comparator orderby, Integer limit, Integer offset); + List getAll(Comparator orderby, Integer limit); + List getAll(Predicate where); + List getAll(Comparator orderby); + List getAll(Integer limit, Integer offset); + List 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); + +} diff --git a/src/com/massivecraft/massivecore/store/EntityContainerAbstract.java b/src/com/massivecraft/massivecore/store/EntityContainerAbstract.java new file mode 100644 index 00000000..db89f061 --- /dev/null +++ b/src/com/massivecraft/massivecore/store/EntityContainerAbstract.java @@ -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> implements EntityContainer +{ + // -------------------------------------------- // + // STORAGE + // -------------------------------------------- // + + @Override public Map 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 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 getAll() + { + return this.getIdToEntity().values(); + } + + @Override public List getAll(Iterable oids, Predicate where, Comparator orderby, Integer limit, Integer offset) { return MUtil.transform(this.getAll(oids), where, orderby, limit, offset); } + @Override public List getAll(Iterable oids, Predicate where, Comparator orderby, Integer limit) { return MUtil.transform(this.getAll(oids), where, orderby, limit); } + @Override public List getAll(Iterable oids, Predicate where, Comparator orderby) { return MUtil.transform(this.getAll(oids), where, orderby); } + @Override public List getAll(Iterable oids, Predicate where, Integer limit, Integer offset) { return MUtil.transform(this.getAll(oids), where, limit, offset); } + @Override public List getAll(Iterable oids, Predicate where, Integer limit) { return MUtil.transform(this.getAll(oids), where, limit); } + @Override public List getAll(Iterable oids, Comparator orderby, Integer limit, Integer offset) { return MUtil.transform(this.getAll(oids), limit, offset); } + @Override public List getAll(Iterable oids, Comparator orderby, Integer limit) { return MUtil.transform(this.getAll(oids), limit); } + @Override public List getAll(Iterable oids, Predicate where) { return MUtil.transform(this.getAll(oids), where); } + @Override public List getAll(Iterable oids, Comparator orderby) { return MUtil.transform(this.getAll(oids), orderby); } + @Override public List getAll(Iterable oids, Integer limit, Integer offset) { return MUtil.transform(this.getAll(oids), limit, offset); } + @Override public List getAll(Iterable oids, Integer limit) { return MUtil.transform(this.getAll(oids), limit); } + + @Override public List getAll(Iterable oids) + { + // Return Create + List 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 getAll(Predicate where, Comparator orderby, Integer limit, Integer offset) { return MUtil.transform(this.getAll(), where, orderby, limit, offset); } + @Override public List getAll(Predicate where, Comparator orderby, Integer limit) { return MUtil.transform(this.getAll(), where, orderby, limit); } + @Override public List getAll(Predicate where, Comparator orderby) { return MUtil.transform(this.getAll(), where, orderby); } + @Override public List getAll(Predicate where, Integer limit, Integer offset) { return MUtil.transform(this.getAll(), where, limit, offset); } + @Override public List getAll(Predicate where, Integer limit) { return MUtil.transform(this.getAll(), where, limit); } + @Override public List getAll(Comparator orderby, Integer limit, Integer offset) { return MUtil.transform(this.getAll(), limit, offset); } + @Override public List getAll(Comparator orderby, Integer limit) { return MUtil.transform(this.getAll(), limit); } + @Override public List getAll(Predicate where) { return MUtil.transform(this.getAll(), where); } + @Override public List getAll(Comparator orderby) { return MUtil.transform(this.getAll(), orderby); } + @Override public List getAll(Integer limit, Integer offset) { return MUtil.transform(this.getAll(), limit, offset); } + @Override public List 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 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; + } + +} diff --git a/src/com/massivecraft/massivecore/store/EntityInternal.java b/src/com/massivecraft/massivecore/store/EntityInternal.java new file mode 100644 index 00000000..51186fd5 --- /dev/null +++ b/src/com/massivecraft/massivecore/store/EntityInternal.java @@ -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> +{ + // -------------------------------------------- // + // FIELDS + // -------------------------------------------- // + + protected transient WeakReference> container = new WeakReference<>(null); + protected void setContainer(EntityContainer container) + { + this.container = new WeakReference<>(container); + } + public EntityContainer 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 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 convertGet(T value, T standard) + { + return value != null ? value : standard; + } + + public 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()); + } + +} diff --git a/src/com/massivecraft/massivecore/store/EntityInternalMap.java b/src/com/massivecraft/massivecore/store/EntityInternalMap.java new file mode 100644 index 00000000..cd9bc66d --- /dev/null +++ b/src/com/massivecraft/massivecore/store/EntityInternalMap.java @@ -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> extends EntityContainerAbstract +{ + // -------------------------------------------- // + // CONSTRUCT + // -------------------------------------------- // + + private EntityInternalMap() + { + this.entityClass = null; + } + + public EntityInternalMap(Class entityClass) + { + this.entityClass = entityClass; + } + + public EntityInternalMap(EntityInternal entity, Class entityClass) + { + Objects.requireNonNull(entity, "entity"); + Objects.requireNonNull(entityClass, "entityClass"); + + this.setEntity(entity); + this.entityClass = entityClass; + } + + // -------------------------------------------- // + // REFERENCE + // -------------------------------------------- // + + protected transient WeakReference> entity = new WeakReference<>(null); + protected void setEntity(EntityInternal entity) { this.entity = new WeakReference>(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 entityClass; + @Override public Class getEntityClass() { return this.entityClass; } + + // -------------------------------------------- // + // STORAGE + // -------------------------------------------- // + + private final ConcurrentHashMap id2Entity = new ConcurrentHashMap<>(); + + @Override public Map getIdToEntityRaw() { return this.id2Entity; } + + // -------------------------------------------- // + // REFERENCE + // -------------------------------------------- // + + @Override + public Coll getColl() + { + return this.getEntity().getContainer().getColl(); + } + + // -------------------------------------------- // + // LOAD + // -------------------------------------------- // + + public EntityInternalMap load(EntityInternalMap that) + { + Objects.requireNonNull(that, "that"); + + // Loop over all the entities in that + for (Entry 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> removals = new MassiveSet<>(); + + // Loop over all current entries ... + for (Iterator> it = this.id2Entity.entrySet().iterator(); it.hasNext(); ) + { + Entry 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 removal : removals) + { + this.detachFixed(removal.getValue(), removal.getKey()); + } + } + + return this; + } + + // -------------------------------------------- // + // IDENTIFIED MODIFICATIONS + // -------------------------------------------- // + + protected Map 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> entrySet() + { + return this.getIdToEntityRaw().entrySet(); + } + public Set 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(); + } + +} diff --git a/src/com/massivecraft/massivecore/store/accessor/Accessor.java b/src/com/massivecraft/massivecore/store/accessor/Accessor.java index 012cd4a5..482849ec 100644 --- a/src/com/massivecraft/massivecore/store/accessor/Accessor.java +++ b/src/com/massivecraft/massivecore/store/accessor/Accessor.java @@ -1,5 +1,7 @@ package com.massivecraft.massivecore.store.accessor; +import com.massivecraft.massivecore.store.EntityInternalMap; + import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; @@ -72,11 +74,23 @@ public class Accessor { String fieldName = entry.getKey(); Field field = entry.getValue(); - FieldAccessor fieldAccessor = new FieldAccessor(field); + FieldAccessor fieldAccessor = createFieldAccessor(field); 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 // -------------------------------------------- // diff --git a/src/com/massivecraft/massivecore/store/accessor/FieldAccessor.java b/src/com/massivecraft/massivecore/store/accessor/FieldAccessor.java index d68a181f..557a94b4 100644 --- a/src/com/massivecraft/massivecore/store/accessor/FieldAccessor.java +++ b/src/com/massivecraft/massivecore/store/accessor/FieldAccessor.java @@ -1,54 +1,8 @@ package com.massivecraft.massivecore.store.accessor; -import com.massivecraft.massivecore.util.ReflectionUtil; - -import java.lang.reflect.Field; - -public class FieldAccessor +public interface FieldAccessor { - // -------------------------------------------- // - // FIELDS - // -------------------------------------------- // - - 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(); - } - } + public Object get(Object entity); + public void set(Object entity, Object val); } diff --git a/src/com/massivecraft/massivecore/store/accessor/FieldAccessorInternalEntityMap.java b/src/com/massivecraft/massivecore/store/accessor/FieldAccessorInternalEntityMap.java new file mode 100644 index 00000000..a3a7cbfe --- /dev/null +++ b/src/com/massivecraft/massivecore/store/accessor/FieldAccessorInternalEntityMap.java @@ -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); + } + +} diff --git a/src/com/massivecraft/massivecore/store/accessor/FieldAccessorSimple.java b/src/com/massivecraft/massivecore/store/accessor/FieldAccessorSimple.java new file mode 100644 index 00000000..935b6bf6 --- /dev/null +++ b/src/com/massivecraft/massivecore/store/accessor/FieldAccessorSimple.java @@ -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(); + } + } + +} diff --git a/src/com/massivecraft/massivecore/store/migrator/MigratorFieldConvert.java b/src/com/massivecraft/massivecore/store/migrator/MigratorFieldConvert.java index 13a2b3e0..a33ff61c 100644 --- a/src/com/massivecraft/massivecore/store/migrator/MigratorFieldConvert.java +++ b/src/com/massivecraft/massivecore/store/migrator/MigratorFieldConvert.java @@ -44,7 +44,7 @@ public abstract class MigratorFieldConvert implements Migrator else if (object instanceof Boolean) return new JsonPrimitive((Boolean) object); else if (object instanceof Character) return new JsonPrimitive((Character) object); else if (object instanceof Number) return new JsonPrimitive((Number) object); - + throw new IllegalArgumentException("Unvalid JsonElement: " + object); }