diff --git a/pom.xml b/pom.xml
index 5ead887..8b1b990 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
it.cavallium
strangedb
- 1.5.5
+ 1.5.7
strangedb-java
https://git.ignuranza.net/andreacavalli/strangedb
@@ -45,7 +45,7 @@
it.cavallium
strangedb-core
- 1.5.5
+ 1.5.7
diff --git a/src/main/java/it/cavallium/strangedb/java/annotations/DbField.java b/src/main/java/it/cavallium/strangedb/java/annotations/DbField.java
index 489b1a1..1ea47df 100644
--- a/src/main/java/it/cavallium/strangedb/java/annotations/DbField.java
+++ b/src/main/java/it/cavallium/strangedb/java/annotations/DbField.java
@@ -10,4 +10,5 @@ import java.lang.annotation.Target;
public @interface DbField {
int id();
DbDataType type() default DbDataType.OBJECT;
+ String name() default "";
}
diff --git a/src/main/java/it/cavallium/strangedb/java/annotations/DbPrimitiveField.java b/src/main/java/it/cavallium/strangedb/java/annotations/DbPrimitiveField.java
index eb50598..aad0385 100644
--- a/src/main/java/it/cavallium/strangedb/java/annotations/DbPrimitiveField.java
+++ b/src/main/java/it/cavallium/strangedb/java/annotations/DbPrimitiveField.java
@@ -10,4 +10,5 @@ import java.lang.annotation.Target;
public @interface DbPrimitiveField {
int id();
DbPrimitiveType type();
+ String name() default "";
}
diff --git a/src/main/java/it/cavallium/strangedb/java/annotations/DbProperty.java b/src/main/java/it/cavallium/strangedb/java/annotations/DbProperty.java
new file mode 100644
index 0000000..8258179
--- /dev/null
+++ b/src/main/java/it/cavallium/strangedb/java/annotations/DbProperty.java
@@ -0,0 +1,14 @@
+package it.cavallium.strangedb.java.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface DbProperty {
+ int id();
+ DbDataType type() default DbDataType.OBJECT;
+ String name() default "";
+}
diff --git a/src/main/java/it/cavallium/strangedb/java/annotations/DbPropertyGetter.java b/src/main/java/it/cavallium/strangedb/java/annotations/DbPropertyGetter.java
index 808045e..43e4522 100644
--- a/src/main/java/it/cavallium/strangedb/java/annotations/DbPropertyGetter.java
+++ b/src/main/java/it/cavallium/strangedb/java/annotations/DbPropertyGetter.java
@@ -8,6 +8,4 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DbPropertyGetter {
- int id();
- DbDataType type() default DbDataType.OBJECT;
}
diff --git a/src/main/java/it/cavallium/strangedb/java/annotations/DbPropertySetter.java b/src/main/java/it/cavallium/strangedb/java/annotations/DbPropertySetter.java
index b7f5593..b6debbd 100644
--- a/src/main/java/it/cavallium/strangedb/java/annotations/DbPropertySetter.java
+++ b/src/main/java/it/cavallium/strangedb/java/annotations/DbPropertySetter.java
@@ -8,6 +8,4 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DbPropertySetter {
- int id();
- DbDataType type() default DbDataType.OBJECT;
}
diff --git a/src/main/java/it/cavallium/strangedb/java/database/DatabaseDataInitializer.java b/src/main/java/it/cavallium/strangedb/java/database/DatabaseDataInitializer.java
index 792fd7f..83f5498 100644
--- a/src/main/java/it/cavallium/strangedb/java/database/DatabaseDataInitializer.java
+++ b/src/main/java/it/cavallium/strangedb/java/database/DatabaseDataInitializer.java
@@ -26,7 +26,7 @@ public class DatabaseDataInitializer implements IDataInitializer {
}
private void initializeDbObjectFields(EnhancedObject obj) throws IOException {
- // Declare the variables needed to get the biggest field Id
+ // Declare the variables needed to getBlock the biggest field Id
Field[] unorderedFields = objectsIO.getFields(obj);
// Find the biggest field Id
int biggestFieldId = objectsIO.getBiggestFieldId(unorderedFields);
@@ -52,7 +52,7 @@ public class DatabaseDataInitializer implements IDataInitializer {
}
private void initializeDbObjectPrimitiveFields(EnhancedObject obj) throws IOException {
- // Declare the variables needed to get the biggest field Id
+ // Declare the variables needed to getBlock the biggest field Id
Field[] unorderedFields = objectsIO.getPrimitiveFields(obj);
// Find the biggest field Id
int biggestFieldId = objectsIO.getBiggestPrimitiveFieldId(unorderedFields);
@@ -107,7 +107,7 @@ public class DatabaseDataInitializer implements IDataInitializer {
}
private void initializeDbObjectProperties(EnhancedObject obj) throws IOException {
- // Declare the variables needed to get the biggest property Id
+ // Declare the variables needed to getBlock the biggest property Id
Method[] unorderedPropertyGetters = obj.getPropertyGetters();
Method[] unorderedPropertySetters = obj.getPropertySetters();
@@ -120,7 +120,7 @@ public class DatabaseDataInitializer implements IDataInitializer {
long[] propertyUIDs = objectsIO.allocateNewUIDs(biggestPropertyId + 1);
for (Method property : unorderedPropertySetters) {
- DbPropertySetter fieldAnnotation = property.getAnnotation(DbPropertySetter.class);
+ DbProperty fieldAnnotation = property.getAnnotation(DbProperty.class);
int propertyId = fieldAnnotation.id();
if (propertyId > biggestPropertyId) {
biggestPropertyId = propertyId;
@@ -131,12 +131,12 @@ public class DatabaseDataInitializer implements IDataInitializer {
DbDataType[] propertyTypes = new DbDataType[biggestPropertyId + 1];
Method[] propertyGetters = new Method[biggestPropertyId + 1];
Method[] propertySetters = new Method[biggestPropertyId + 1];
- Map setterMethods = new LinkedHashMap<>();
- Map getterMethods = new LinkedHashMap<>();
+ Map setterMethods = new LinkedHashMap<>();
+ Map getterMethods = new LinkedHashMap<>();
// Load the properties metadata
for (Method property : unorderedPropertyGetters) {
- DbPropertyGetter propertyAnnotation = property.getAnnotation(DbPropertyGetter.class);
+ DbProperty propertyAnnotation = property.getAnnotation(DbProperty.class);
int propertyId = propertyAnnotation.id();
DbDataType propertyType = propertyAnnotation.type();
propertyTypes[propertyId] = propertyType;
@@ -144,7 +144,7 @@ public class DatabaseDataInitializer implements IDataInitializer {
getterMethods.put(property.getName(), propertyAnnotation);
}
for (Method property : unorderedPropertySetters) {
- DbPropertySetter propertyAnnotation = property.getAnnotation(DbPropertySetter.class);
+ DbProperty propertyAnnotation = property.getAnnotation(DbProperty.class);
int propertyId = propertyAnnotation.id();
DbDataType propertyType = propertyAnnotation.type();
propertyTypes[propertyId] = propertyType;
diff --git a/src/main/java/it/cavallium/strangedb/java/database/DatabaseEnhancedObjectUpgrader.java b/src/main/java/it/cavallium/strangedb/java/database/DatabaseEnhancedObjectUpgrader.java
index c820dfa..96d73d7 100644
--- a/src/main/java/it/cavallium/strangedb/java/database/DatabaseEnhancedObjectUpgrader.java
+++ b/src/main/java/it/cavallium/strangedb/java/database/DatabaseEnhancedObjectUpgrader.java
@@ -23,14 +23,14 @@ public class DatabaseEnhancedObjectUpgrader implements EnhancedObjectUpgrader {
@Override
@SuppressWarnings("unchecked")
- public Object getField(int id, DbDataType type, Supplier> enhancedClassType) throws IOException {
- return objectsIO.loadData(type, fieldRefs[id], enhancedClassType);
+ public Object getField(int id, DbDataType type) throws IOException {
+ return objectsIO.loadData(type, fieldRefs[id]);
}
@Override
@SuppressWarnings("unchecked")
- public Object getMethod(int id, DbDataType type, Supplier> enhancedClassType) throws IOException {
- return objectsIO.loadData(type, methodRefs[id], enhancedClassType);
+ public Object getMethod(int id, DbDataType type) throws IOException {
+ return objectsIO.loadData(type, methodRefs[id]);
}
@SuppressWarnings("unchecked")
diff --git a/src/main/java/it/cavallium/strangedb/java/database/DatabaseJava.java b/src/main/java/it/cavallium/strangedb/java/database/DatabaseJava.java
index 630834f..f434515 100644
--- a/src/main/java/it/cavallium/strangedb/java/database/DatabaseJava.java
+++ b/src/main/java/it/cavallium/strangedb/java/database/DatabaseJava.java
@@ -1,21 +1,38 @@
package it.cavallium.strangedb.java.database;
import it.cavallium.strangedb.database.DatabaseCore;
+import it.cavallium.strangedb.database.references.ReferenceInfo;
import it.cavallium.strangedb.java.objects.EnhancedObject;
import it.cavallium.strangedb.functionalinterfaces.FunctionWithIO;
+import it.cavallium.strangedb.java.objects.EnhancedObjectIndices;
+import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.longs.LongArrayList;
+import it.unimi.dsi.fastutil.longs.LongArraySet;
+import it.unimi.dsi.fastutil.longs.LongSet;
+import it.unimi.dsi.fastutil.objects.ObjectIterator;
import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+
+import static it.cavallium.strangedb.database.references.DatabaseReferencesMetadata.*;
+import static it.cavallium.strangedb.java.database.DatabaseObjectsIO.ENHANCED_OBJECT_METADATA_CLEANER;
+import static it.cavallium.strangedb.java.database.DatabaseObjectsIO.REFERENCES_LIST_CLEANER;
public class DatabaseJava extends DatabaseCore implements IDatabaseTools {
private final IDatabaseTools databaseTools;
private final DatabaseObjectsIO objectsIO;
private EnhancedObject loadedRootObject;
+ private boolean hasLoadedRootObject;
public DatabaseJava(Path dataFile, Path blocksMetaFile, Path referencesMetaFile) throws IOException {
super(dataFile, blocksMetaFile, referencesMetaFile);
this.databaseTools = this;
this.objectsIO = new DatabaseObjectsIO(databaseTools, referencesIO);
+ this.hasLoadedRootObject = false;
}
@Override
@@ -23,17 +40,19 @@ public class DatabaseJava extends DatabaseCore implements IDatabaseTools {
if (this.closed) {
throw new IOException("The database has been already closed!");
}
- this.objectsIO.setEnhancedObject(0, loadedRootObject);
+ if (hasLoadedRootObject) {
+ this.objectsIO.setEnhancedObject(0, loadedRootObject);
+ }
super.close();
}
- public T loadRoot(Class type, FunctionWithIO ifAbsent) throws IOException {
- if (loadedRootObject != null) {
+ public T loadRoot(FunctionWithIO ifAbsent) throws IOException {
+ if (hasLoadedRootObject) {
throw new RuntimeException("Root already set!");
}
T root;
if (referencesMetadata.getFirstFreeReference() > 0) {
- root = objectsIO.loadEnhancedObject(0, type);
+ root = objectsIO.loadEnhancedObject(0);
} else {
if (objectsIO.newNullObject() != 0) {
throw new IOException("Can't allocate root!");
@@ -43,13 +62,110 @@ public class DatabaseJava extends DatabaseCore implements IDatabaseTools {
}
}
loadedRootObject = root;
+ hasLoadedRootObject = true;
return root;
}
+ @Override
+ public void closeAndClean() throws IOException {
+ if (!this.closed) {
+ this.close();
+ }
+ Path newDataFile = dataFile.resolveSibling("compressed-data-file.tmp");
+ Path newBlocksFile = blocksMetaFile.resolveSibling("compressed-blocks-file.tmp");
+ Path newReferencesFile = referencesMetaFile.resolveSibling("compressed-references-file.tmp");
+ Path backupDataFile = dataFile.resolveSibling("backup-data.db.bak");
+ Path backupBlocksFile = blocksMetaFile.resolveSibling("backup-blocks.dat.bak");
+ Path backupReferencesFile = referencesMetaFile.resolveSibling("backup-references.dat.bak");
+ Files.copy(dataFile, backupDataFile, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
+ Files.copy(blocksMetaFile, backupBlocksFile, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
+ Files.copy(referencesMetaFile, backupReferencesFile, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
+ Files.move(dataFile, newDataFile, StandardCopyOption.REPLACE_EXISTING);
+ Files.move(blocksMetaFile, newBlocksFile, StandardCopyOption.REPLACE_EXISTING);
+ Files.move(referencesMetaFile, newReferencesFile, StandardCopyOption.REPLACE_EXISTING);
+ DatabaseJava databaseToClean = instantiateNewDatabase(newDataFile, newBlocksFile, newReferencesFile);
+ DatabaseJava newDatabase = instantiateNewDatabase(dataFile, blocksMetaFile, referencesMetaFile);
+
+ long firstFreeReference = databaseToClean.referencesMetadata.getFirstFreeReference();
+ long referencesCount = 0;
+ long blocksCount = databaseToClean.blocksMetadata.getTotalBlocksCount();
+ long writtenReferences = 0;
+ long writtenBlocks = 0;
+
+ LongArrayList idsToKeep = new LongArrayList();
+ cleanRef(databaseToClean, idsToKeep, 0);
+
+ for (int referenceID = 0; referenceID < firstFreeReference; referenceID++) {
+ try {
+ ReferenceInfo ref = databaseToClean.referencesMetadata.getReference(referenceID);
+ if (!NONEXISTENT_REFERENCE_INFO.equals(ref)) {
+ referencesCount++;
+ if (idsToKeep.contains(referenceID)) {
+ ByteBuffer buffer = databaseToClean.referencesIO.readFromReference(referenceID);
+ newDatabase.referencesIO.writeToReference(referenceID, ref.getCleanerId(), buffer.limit(), buffer);
+ writtenReferences++;
+ if (buffer.limit() > 0) {
+ writtenBlocks++;
+ }
+ }
+ }
+ } catch (IOException ex) {
+ System.out.println("Error while reading reference " + referenceID + ". References written: " + writtenReferences);
+ }
+ }
+ System.out.println("[Java Cleaner] References written: " + writtenReferences + ". Removed " + (blocksCount - writtenBlocks) + " blocks. Removed " + (referencesCount - writtenReferences) + " references.");
+ databaseToClean.close();
+ newDatabase.close();
+ Files.deleteIfExists(newDataFile);
+ Files.deleteIfExists(newBlocksFile);
+ Files.deleteIfExists(newReferencesFile);
+ }
+
+ private void cleanRef(DatabaseJava db, LongArrayList idsToKeep, long ref) throws IOException {
+ idsToKeep.add(ref);
+ ReferenceInfo refInfo = db.referencesMetadata.getReference(ref);
+ if (!NONEXISTENT_REFERENCE_INFO.equals(refInfo)) {
+ switch (refInfo.getCleanerId()) {
+ case ENHANCED_OBJECT_METADATA_CLEANER: {
+ EnhancedObjectIndices enhancedObjectUids = db.objectsIO.loadEnhancedObjectUids(ref);
+ for (long fieldUid : enhancedObjectUids.fieldUids) {
+ cleanRef(db, idsToKeep, fieldUid);
+ }
+ for (long propUid : enhancedObjectUids.propertyUids) {
+ cleanRef(db, idsToKeep, propUid);
+ }
+ cleanRef(db, idsToKeep, enhancedObjectUids.nativeDataUid);
+ break;
+ }
+ case ERRORED_CLEANER: {
+ System.err.println("Errored cleaner found! Skipping...");
+ break;
+ }
+ case REFERENCES_LIST_CLEANER: {
+ LongArrayList refList = db.objectsIO.loadReferencesList(ref);
+ for (long elemRef : refList) {
+ cleanRef(db, idsToKeep, elemRef);
+ }
+ break;
+ }
+ case BLANK_DATA_CLEANER: {
+ break;
+ }
+ default: {
+ System.err.println("Unrecognized cleaner found! Skipping...");
+ }
+ }
+ }
+ }
+
protected void registerClass(Class> type, int id) {
this.objectsIO.registerClass(type, id);
}
+ protected DatabaseJava instantiateNewDatabase(Path dataFile, Path blocksMetaFile, Path referencesMetaFile) throws IOException {
+ return new DatabaseJava(dataFile, blocksMetaFile, referencesMetaFile);
+ }
+
@Override
public void initializeEnhancedObject(EnhancedObject enhancedObject) throws IOException {
this.objectsIO.getDataInitializer().initializeDbObject(enhancedObject);
diff --git a/src/main/java/it/cavallium/strangedb/java/database/DatabaseObjectsIO.java b/src/main/java/it/cavallium/strangedb/java/database/DatabaseObjectsIO.java
index 5e2dde1..e630ffa 100644
--- a/src/main/java/it/cavallium/strangedb/java/database/DatabaseObjectsIO.java
+++ b/src/main/java/it/cavallium/strangedb/java/database/DatabaseObjectsIO.java
@@ -3,10 +3,14 @@ package it.cavallium.strangedb.java.database;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
-import it.cavallium.strangedb.java.objects.EnhancedObject;
-import it.cavallium.strangedb.java.objects.EnhancedObjectFullInfo;
import it.cavallium.strangedb.database.references.DatabaseReferencesIO;
import it.cavallium.strangedb.java.annotations.*;
+import it.cavallium.strangedb.java.objects.EnhancedObject;
+import it.cavallium.strangedb.java.objects.EnhancedObjectFullInfo;
+import it.cavallium.strangedb.java.objects.EnhancedObjectIndices;
+import it.cavallium.strangedb.java.objects.lists.EnhancedObjectStrangeDbList;
+import it.cavallium.strangedb.java.objects.lists.ObjectStrangeDbList;
+import it.cavallium.strangedb.java.objects.lists.StrangeDbList;
import it.unimi.dsi.fastutil.booleans.BooleanArrayList;
import it.unimi.dsi.fastutil.bytes.ByteArrayList;
import it.unimi.dsi.fastutil.chars.CharArrayList;
@@ -23,14 +27,20 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.*;
-import java.util.function.Supplier;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import static it.cavallium.strangedb.database.references.DatabaseReferencesMetadata.BLANK_DATA_CLEANER;
public class DatabaseObjectsIO implements IObjectsIO {
+ public static final byte ENHANCED_OBJECT_METADATA_CLEANER = 1;
+ public static final byte REFERENCES_LIST_CLEANER = 2;
+
private final IDatabaseTools databaseTools;
private final DatabaseReferencesIO referencesIO;
- private final Object accessLock = new Object();
+ private final Lock lock = new ReentrantLock();
private final DatabaseDataInitializer dataInitializer;
private Kryo kryo = new Kryo();
@@ -92,16 +102,68 @@ public class DatabaseObjectsIO implements IObjectsIO {
registerClass(TreeSet.class, id++);
registerClass(SortedSet.class, id++);
registerClass(SortedMap.class, id++);
+
+ registerClass(EnhancedObject.class, id++);
+ registerClass(EnhancedObjectStrangeDbList.class, id++);
+ registerClass(ObjectStrangeDbList.class, id++);
+ registerClass(StrangeDbList.class, id++);
}
@Override
- public T loadEnhancedObject(long reference, Class objectType) throws IOException {
- synchronized (accessLock) {
+ public T loadEnhancedObject(long reference) throws IOException {
+ lock.lock();
+ try {
+ return loadEnhancedObject_(reference);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private T loadEnhancedObject_(long reference) throws IOException {
+ ByteBuffer buffer = referencesIO.readFromReference(reference);
+ if (buffer.limit() == 0) {
+ return null;
+ }
+ int serializedVersion = Byte.toUnsignedInt(buffer.get()) - 5;
+ if (serializedVersion < 0) {
+ System.err.println("PLEASE UPGRADE THE DATABASE");
+ throw new IllegalAccessError("PLEASE UPGRADE THE DATABASE");
+ }
+ int serializedClassLength = Byte.toUnsignedInt(buffer.get());
+ byte[] serializedClassData = new byte[serializedClassLength];
+ buffer.get(serializedClassData);
+ Class objectType = kryo.readClass(new Input(serializedClassData)).getType();
+ int fieldsCount = buffer.getInt();
+ int methodsCount = buffer.getInt();
+ long[] fieldRefs = new long[fieldsCount];
+ long[] methodRefs = new long[methodsCount];
+ for (int i = 0; i < fieldsCount; i++) {
+ fieldRefs[i] = buffer.getLong();
+ }
+ for (int i = 0; i < methodsCount; i++) {
+ methodRefs[i] = buffer.getLong();
+ }
+ long nativeFieldsDataReference = buffer.getLong();
+ return preloadEnhancedObject(objectType, serializedVersion, nativeFieldsDataReference, fieldRefs,
+ methodRefs);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public EnhancedObjectIndices loadEnhancedObjectUids(long reference) throws IOException {
+ lock.lock();
+ try {
ByteBuffer buffer = referencesIO.readFromReference(reference);
if (buffer.limit() == 0) {
return null;
}
- int serializedVersion = Byte.toUnsignedInt(buffer.get());
+ //noinspection unused
+ int serializedVersion = Byte.toUnsignedInt(buffer.get()) - 5;
+ int serializedClassLength = Byte.toUnsignedInt(buffer.get());
+ byte[] serializedClassData = new byte[serializedClassLength];
+ buffer.get(serializedClassData);
+ Class extends EnhancedObject> objectType = (Class extends EnhancedObject>) kryo.readClass(new Input(serializedClassData)).getType();
int fieldsCount = buffer.getInt();
int methodsCount = buffer.getInt();
long[] fieldRefs = new long[fieldsCount];
@@ -113,40 +175,50 @@ public class DatabaseObjectsIO implements IObjectsIO {
methodRefs[i] = buffer.getLong();
}
long nativeFieldsDataReference = buffer.getLong();
- return preloadEnhancedObject(objectType, serializedVersion, nativeFieldsDataReference, fieldRefs,
- methodRefs);
+ return new EnhancedObjectIndices(objectType, reference, fieldRefs, methodRefs, nativeFieldsDataReference);
+ } finally {
+ lock.unlock();
}
}
- @SuppressWarnings("unchecked")
- Object loadData(DbDataType propertyType, long dataReference, Supplier> returnType) throws IOException {
+ public Object loadData(DbDataType propertyType, long dataReference) throws IOException {
+ lock.lock();
+ try {
+ return loadData_(propertyType, dataReference);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private Object loadData_(DbDataType propertyType, long dataReference) throws IOException {
+
switch (propertyType) {
case ENHANCED_OBJECT:
- return loadEnhancedObject(dataReference, (Class extends EnhancedObject>) returnType.get());
+ return loadEnhancedObject_(dataReference);
case OBJECT:
- return loadObject(dataReference);
+ return loadObject_(dataReference);
case REFERENCES_LIST:
- return loadReferencesList(dataReference);
+ return loadReferencesList_(dataReference);
default:
throw new NullPointerException("Unknown data type");
}
}
- void setData(long reference, DbDataType propertyType, T loadedPropertyValue) throws IOException {
+ private void setData(long reference, DbDataType propertyType, T loadedPropertyValue) throws IOException {
switch (propertyType) {
case OBJECT:
- setObject(reference, loadedPropertyValue);
+ setObject_(reference, loadedPropertyValue);
break;
case REFERENCES_LIST:
- setReferencesList(reference, (LongArrayList) loadedPropertyValue);
+ setReferencesList_(reference, (LongArrayList) loadedPropertyValue);
break;
case ENHANCED_OBJECT:
- setEnhancedObject(reference, (EnhancedObject) loadedPropertyValue);
+ setEnhancedObject_(reference, (EnhancedObject) loadedPropertyValue);
break;
}
}
- void setPrimitives(T enhancedObject, long reference, DbPrimitiveType[] types, Field[] fields)
+ private void setPrimitives(T enhancedObject, long reference, DbPrimitiveType[] types, Field[] fields)
throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES * fields.length);
try {
@@ -188,160 +260,219 @@ public class DatabaseObjectsIO implements IObjectsIO {
throw new IOException(e);
}
buffer.flip();
- referencesIO.writeToReference(reference, buffer.limit(), buffer);
+ referencesIO.writeToReference(reference, BLANK_DATA_CLEANER, buffer.limit(), buffer);
}
@Override
public void setEnhancedObject(long reference, T value) throws IOException {
- synchronized (accessLock) {
- if (value != null) {
- EnhancedObjectFullInfo objectFullInfo = value.getAllInfo();
- if (objectFullInfo == null || objectFullInfo.getFieldReferences() == null
- || objectFullInfo.getPropertyReferences() == null) {
- throw new NullPointerException(
- "An EnhancedObject has been initialized using the empty constructor!");
- }
+ lock.lock();
+ try {
+ setEnhancedObject_(reference, value);
+ } finally {
+ lock.unlock();
+ }
+ }
- final long[] fieldReferences = objectFullInfo.getFieldReferences();
- final DbDataType[] fieldTypes = objectFullInfo.getFieldTypes();
- final Field[] fields = objectFullInfo.getFields();
- final long nativeFieldDataReference = objectFullInfo.getPrimitiveFieldDataReference();
- final DbPrimitiveType[] nativeFieldTypes = objectFullInfo.getPrimitiveFieldTypes();
- final Field[] nativeFields = objectFullInfo.getPrimitiveFields();
- final long[] propertyReferences = objectFullInfo.getPropertyReferences();
- final DbDataType[] propertyTypes = objectFullInfo.getPropertyTypes();
- final Object[] propertyValues = objectFullInfo.getLoadedPropertyValues();
- final int totalSize = Byte.BYTES + Integer.BYTES * 2 + fieldReferences.length * Long.BYTES
- + propertyReferences.length * Long.BYTES + Long.BYTES;
- ByteBuffer buffer = ByteBuffer.allocate(totalSize);
- buffer.put((byte) objectFullInfo.getVersion());
- buffer.putInt(fieldReferences.length);
- buffer.putInt(propertyReferences.length);
- for (int i = 0; i < fieldReferences.length; i++) {
- buffer.putLong(fieldReferences[i]);
- }
- for (int i = 0; i < propertyReferences.length; i++) {
- buffer.putLong(propertyReferences[i]);
- }
- buffer.putLong(nativeFieldDataReference);
- buffer.flip();
-
- for (int i = 0; i < fieldReferences.length; i++) {
- if (fields[i] != null) {
- try {
- setData(fieldReferences[i], fieldTypes[i], fields[i].get(value));
- } catch (IllegalAccessException e) {
- throw new IOException(e);
- }
- }
- }
- for (int i = 0; i < propertyReferences.length; i++) {
- if (propertyValues[i] != null) {
- setData(propertyReferences[i], propertyTypes[i], propertyValues[i]);
- }
- }
- setPrimitives(value, nativeFieldDataReference, nativeFieldTypes, nativeFields);
- referencesIO.writeToReference(reference, totalSize, buffer);
- } else {
- referencesIO.writeToReference(reference, 0, null);
+ private void setEnhancedObject_(long reference, T value) throws IOException {
+ if (value != null) {
+ EnhancedObjectFullInfo objectFullInfo = value.getAllInfo();
+ if (objectFullInfo == null || objectFullInfo.getFieldReferences() == null
+ || objectFullInfo.getPropertyReferences() == null) {
+ throw new NullPointerException(
+ "An EnhancedObject has been initialized using the empty constructor!");
}
+
+ final long[] fieldReferences = objectFullInfo.getFieldReferences();
+ final DbDataType[] fieldTypes = objectFullInfo.getFieldTypes();
+ final Field[] fields = objectFullInfo.getFields();
+ final long nativeFieldDataReference = objectFullInfo.getPrimitiveFieldDataReference();
+ final DbPrimitiveType[] nativeFieldTypes = objectFullInfo.getPrimitiveFieldTypes();
+ final Field[] nativeFields = objectFullInfo.getPrimitiveFields();
+ final long[] propertyReferences = objectFullInfo.getPropertyReferences();
+ final DbDataType[] propertyTypes = objectFullInfo.getPropertyTypes();
+ final Object[] propertyValues = objectFullInfo.getLoadedPropertyValues();
+ Output serializedClassDataStream = new Output(1024, 8192);
+ kryo.writeClass(serializedClassDataStream, value.getClass());
+ byte[] serializedClassData = serializedClassDataStream.toBytes();
+ final int totalSize = Byte.BYTES + serializedClassData.length + Byte.BYTES + Integer.BYTES * 2 + fieldReferences.length * Long.BYTES
+ + propertyReferences.length * Long.BYTES + Long.BYTES;
+ ByteBuffer buffer = ByteBuffer.allocate(totalSize);
+ if (serializedClassData.length > 255) {
+ throw new IndexOutOfBoundsException("The class name is too long!");
+ }
+ if (objectFullInfo.getVersion() > 250) {
+ throw new IndexOutOfBoundsException("The class version is too long!");
+ }
+ buffer.put((byte) (objectFullInfo.getVersion() + 5));
+ buffer.put((byte) serializedClassData.length);
+ buffer.put(serializedClassData);
+ buffer.putInt(fieldReferences.length);
+ buffer.putInt(propertyReferences.length);
+ for (int i = 0; i < fieldReferences.length; i++) {
+ buffer.putLong(fieldReferences[i]);
+ }
+ for (int i = 0; i < propertyReferences.length; i++) {
+ buffer.putLong(propertyReferences[i]);
+ }
+ buffer.putLong(nativeFieldDataReference);
+ buffer.flip();
+
+ for (int i = 0; i < fieldReferences.length; i++) {
+ if (fields[i] != null) {
+ try {
+ setData(fieldReferences[i], fieldTypes[i], fields[i].get(value));
+ } catch (IllegalAccessException e) {
+ throw new IOException(e);
+ }
+ }
+ }
+ for (int i = 0; i < propertyReferences.length; i++) {
+ if (propertyValues[i] != null) {
+ setData(propertyReferences[i], propertyTypes[i], propertyValues[i]);
+ }
+ }
+ setPrimitives(value, nativeFieldDataReference, nativeFieldTypes, nativeFields);
+ referencesIO.writeToReference(reference, ENHANCED_OBJECT_METADATA_CLEANER, totalSize, buffer);
+ } else {
+ referencesIO.writeToReference(reference, BLANK_DATA_CLEANER, 0, null);
+ }
+ }
+
+ @Override
+ public T loadObject(long reference) throws IOException {
+ lock.lock();
+ try {
+ return loadObject_(reference);
+ } finally {
+ lock.unlock();
}
}
@SuppressWarnings("unchecked")
- @Override
- public T loadObject(long reference) throws IOException {
- synchronized (accessLock) {
- ByteBuffer buffer = referencesIO.readFromReference(reference);
- if (buffer.limit() == 0) {
- return null;
- }
- buffer.rewind();
- byte[] data = buffer.array();
- return (T) kryo.readClassAndObject(new Input(data));
+ private T loadObject_(long reference) throws IOException {
+ ByteBuffer buffer = referencesIO.readFromReference(reference);
+ if (buffer.limit() == 0) {
+ return null;
}
+ buffer.rewind();
+ byte[] data = buffer.array();
+ return (T) kryo.readClassAndObject(new Input(data));
}
@Override
public LongArrayList loadReferencesList(long reference) throws IOException {
- synchronized (accessLock) {
- ByteBuffer buffer = referencesIO.readFromReference(reference);
- if (buffer.limit() == 0) {
- return null;
- }
- int itemsCount = buffer.getInt();
- LongArrayList arrayList = new LongArrayList();
- for (int i = 0; i < itemsCount; i++) {
- arrayList.add(buffer.getLong());
- }
- return arrayList;
+ lock.lock();
+ try {
+ return loadReferencesList_(reference);
+ } finally {
+ lock.unlock();
}
}
+ private LongArrayList loadReferencesList_(long reference) throws IOException {
+ ByteBuffer buffer = referencesIO.readFromReference(reference);
+ if (buffer.limit() == 0) {
+ return null;
+ }
+ int itemsCount = buffer.getInt();
+ LongArrayList arrayList = new LongArrayList();
+ for (int i = 0; i < itemsCount; i++) {
+ arrayList.add(buffer.getLong());
+ }
+ return arrayList;
+ }
+
@Override
public LongList loadPrimitiveData(long reference) throws IOException {
- synchronized (accessLock) {
- ByteBuffer buffer = referencesIO.readFromReference(reference);
- if (buffer.limit() == 0) {
- return null;
- }
- int size = buffer.limit() / Long.BYTES;
- LongArrayList result = new LongArrayList(size);
- for (int i = 0; i < size; i++) {
- result.add(buffer.getLong());
- }
- return result;
+ lock.lock();
+ try {
+ return loadPrimitiveData_(reference);
+ } finally {
+ lock.unlock();
}
}
+ private LongList loadPrimitiveData_(long reference) throws IOException {
+ ByteBuffer buffer = referencesIO.readFromReference(reference);
+ if (buffer.limit() == 0) {
+ return null;
+ }
+ int size = buffer.limit() / Long.BYTES;
+ LongArrayList result = new LongArrayList(size);
+ for (int i = 0; i < size; i++) {
+ result.add(buffer.getLong());
+ }
+ return result;
+ }
+
@Override
public void setObject(long reference, T value) throws IOException {
- synchronized (accessLock) {
- if (value != null) {
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- Output output = new Output(outputStream);
- kryo.writeClassAndObject(output, value);
- output.flush();
- byte[] data = outputStream.toByteArray();
- ByteBuffer dataByteBuffer = ByteBuffer.wrap(data);
- referencesIO.writeToReference(reference, data.length, dataByteBuffer);
- } else {
- referencesIO.writeToReference(reference, 0, null);
- }
+ lock.lock();
+ try {
+ setObject_(reference, value);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private void setObject_(long reference, T value) throws IOException {
+ if (value != null) {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ Output output = new Output(outputStream);
+ kryo.writeClassAndObject(output, value);
+ output.flush();
+ byte[] data = outputStream.toByteArray();
+ ByteBuffer dataByteBuffer = ByteBuffer.wrap(data);
+ referencesIO.writeToReference(reference, BLANK_DATA_CLEANER, data.length, dataByteBuffer);
+ } else {
+ referencesIO.writeToReference(reference, BLANK_DATA_CLEANER, 0, null);
}
}
@Override
public void setReferencesList(long reference, LongArrayList value) throws IOException {
- synchronized (accessLock) {
- if (value != null) {
- int items = value.size();
- ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES * items + Integer.BYTES);
- buffer.putInt(items);
- for (int i = 0; i < items; i++) {
- buffer.putLong(value.getLong(i));
- }
- buffer.flip();
- referencesIO.writeToReference(reference, buffer.limit(), buffer);
- } else {
- referencesIO.writeToReference(reference, 0, null);
+ lock.lock();
+ try {
+ setReferencesList_(reference, value);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private void setReferencesList_(long reference, LongArrayList value) throws IOException {
+ if (value != null) {
+ int items = value.size();
+ ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES * items + Integer.BYTES);
+ buffer.putInt(items);
+ for (int i = 0; i < items; i++) {
+ buffer.putLong(value.getLong(i));
}
+ buffer.flip();
+ referencesIO.writeToReference(reference, REFERENCES_LIST_CLEANER, buffer.limit(), buffer);
+ } else {
+ referencesIO.writeToReference(reference, REFERENCES_LIST_CLEANER, 0, null);
}
}
@Override
public long newNullObject() throws IOException {
- synchronized (accessLock) {
- return referencesIO.allocateReference();
+ lock.lock();
+ try {
+ return newNullObject_();
+ } finally {
+ lock.unlock();
}
}
+ private long newNullObject_() throws IOException {
+ return referencesIO.allocateReference();
+ }
+
@Override
- public void loadProperty(EnhancedObject obj, int propertyId, Method property, DbDataType propertyType,
+ public void loadProperty(EnhancedObject obj, int propertyId, DbDataType propertyType,
long propertyUID) throws IOException {
- synchronized (accessLock) {
- obj.setProperty(propertyId, loadData(propertyType, propertyUID, property::getReturnType));
- }
+ obj.setProperty(propertyId, loadData_(propertyType, propertyUID));
+ obj.setProperty(propertyId, loadData_(propertyType, propertyUID));
}
@Override
@@ -353,17 +484,17 @@ public class DatabaseObjectsIO implements IObjectsIO {
}
private void preloadEnhancedObjectProperties(T obj, long[] propertyReferences) {
- // Declare the variables needed to get the biggest property Id
+ // Declare the variables needed to getBlock the biggest property Id
Method[] unorderedPropertyGetters = obj.getPropertyGetters();
Method[] unorderedPropertySetters = obj.getPropertySetters();
// Find the biggest property Id
- int biggestGetter = getBiggestPropertyGetterId(unorderedPropertyGetters);
- int biggestSetter = getBiggestPropertySetterId(unorderedPropertySetters);
+ int biggestGetter = getBiggestPropertyGetterId_(unorderedPropertyGetters);
+ int biggestSetter = getBiggestPropertySetterId_(unorderedPropertySetters);
int biggestPropertyId = biggestGetter > biggestSetter ? biggestGetter : biggestSetter;
for (Method property : unorderedPropertySetters) {
- DbPropertySetter fieldAnnotation = property.getAnnotation(DbPropertySetter.class);
+ DbProperty fieldAnnotation = property.getAnnotation(DbProperty.class);
int propertyId = fieldAnnotation.id();
if (propertyId > biggestPropertyId) {
biggestPropertyId = propertyId;
@@ -374,12 +505,12 @@ public class DatabaseObjectsIO implements IObjectsIO {
DbDataType[] propertyTypes = new DbDataType[biggestPropertyId + 1];
Method[] propertyGetters = new Method[biggestPropertyId + 1];
Method[] propertySetters = new Method[biggestPropertyId + 1];
- Map setterMethods = new LinkedHashMap<>();
- Map getterMethods = new LinkedHashMap<>();
+ Map setterMethods = new LinkedHashMap<>();
+ Map getterMethods = new LinkedHashMap<>();
// Load the properties metadata
for (Method property : unorderedPropertyGetters) {
- DbPropertyGetter propertyAnnotation = property.getAnnotation(DbPropertyGetter.class);
+ DbProperty propertyAnnotation = property.getAnnotation(DbProperty.class);
int propertyId = propertyAnnotation.id();
DbDataType propertyType = propertyAnnotation.type();
propertyTypes[propertyId] = propertyType;
@@ -387,7 +518,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
getterMethods.put(property.getName(), propertyAnnotation);
}
for (Method property : unorderedPropertySetters) {
- DbPropertySetter propertyAnnotation = property.getAnnotation(DbPropertySetter.class);
+ DbProperty propertyAnnotation = property.getAnnotation(DbProperty.class);
int propertyId = propertyAnnotation.id();
DbDataType propertyType = propertyAnnotation.type();
propertyTypes[propertyId] = propertyType;
@@ -399,10 +530,19 @@ public class DatabaseObjectsIO implements IObjectsIO {
getterMethods);
}
- int getBiggestPropertyGetterId(Method[] unorderedPropertyGetters) {
+ public int getBiggestPropertyGetterId(Method[] unorderedPropertyGetters) {
+ lock.lock();
+ try {
+ return getBiggestPropertyGetterId_(unorderedPropertyGetters);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private int getBiggestPropertyGetterId_(Method[] unorderedPropertyGetters) {
int biggestPropertyId = -1;
for (Method property : unorderedPropertyGetters) {
- DbPropertyGetter fieldAnnotation = property.getAnnotation(DbPropertyGetter.class);
+ DbProperty fieldAnnotation = property.getAnnotation(DbProperty.class);
int propertyId = fieldAnnotation.id();
if (propertyId > biggestPropertyId) {
biggestPropertyId = propertyId;
@@ -411,10 +551,19 @@ public class DatabaseObjectsIO implements IObjectsIO {
return biggestPropertyId;
}
- int getBiggestPropertySetterId(Method[] unorderedPropertySetters) {
+ public int getBiggestPropertySetterId(Method[] unorderedPropertySetters) {
+ lock.lock();
+ try {
+ return getBiggestPropertySetterId_(unorderedPropertySetters);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private int getBiggestPropertySetterId_(Method[] unorderedPropertySetters) {
int biggestPropertyId = -1;
for (Method property : unorderedPropertySetters) {
- DbPropertySetter fieldAnnotation = property.getAnnotation(DbPropertySetter.class);
+ DbProperty fieldAnnotation = property.getAnnotation(DbProperty.class);
int propertyId = fieldAnnotation.id();
if (propertyId > biggestPropertyId) {
biggestPropertyId = propertyId;
@@ -425,10 +574,10 @@ public class DatabaseObjectsIO implements IObjectsIO {
private void preloadEnhancedObjectPrimitiveFields(T obj, long nativeFieldsDataReference)
throws IOException {
- // Declare the variables needed to get the biggest field Id
- Field[] unorderedFields = getPrimitiveFields(obj);
+ // Declare the variables needed to getBlock the biggest field Id
+ Field[] unorderedFields = getPrimitiveFields_(obj);
// Find the biggest field Id
- int biggestFieldId = getBiggestPrimitiveFieldId(unorderedFields);
+ int biggestFieldId = getBiggestPrimitiveFieldId_(unorderedFields);
// Declare the other variables
Field[] fields = new Field[biggestFieldId + 1];
@@ -489,8 +638,8 @@ public class DatabaseObjectsIO implements IObjectsIO {
private void preloadEnhancedObjectFields(T obj, long[] fieldReferences)
throws IOException {
- // Declare the variables needed to get the biggest field Id
- Field[] unorderedFields = getFields(obj);
+ // Declare the variables needed to getBlock the biggest field Id
+ Field[] unorderedFields = getFields_(obj);
// Find the biggest field Id
int biggestFieldId = getBiggestFieldId(unorderedFields);
@@ -503,7 +652,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
DbField fieldAnnotation = field.getAnnotation(DbField.class);
int fieldId = fieldAnnotation.id();
DbDataType fieldType = fieldAnnotation.type();
- loadField(obj, field, fieldType, fieldReferences[fieldId]);
+ loadField_(obj, field, fieldType, fieldReferences[fieldId]);
fields[fieldId] = field;
orderedFieldTypes[fieldId] = fieldType;
}
@@ -511,9 +660,19 @@ public class DatabaseObjectsIO implements IObjectsIO {
obj.setFields(fields, orderedFieldTypes, fieldReferences);
}
- void loadField(T obj, Field field, DbDataType fieldType, long fieldReference)
+ public void loadField(T obj, Field field, DbDataType fieldType, long fieldReference)
throws IOException {
- Object data = loadData(fieldType, fieldReference, field::getType);
+ lock.lock();
+ try {
+ loadField_(obj, field, fieldType, fieldReference);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private void loadField_(T obj, Field field, DbDataType fieldType, long fieldReference)
+ throws IOException {
+ Object data = loadData_(fieldType, fieldReference);
try {
if (fieldType == DbDataType.OBJECT && data != null) {
if (!field.getType().isInstance(data)) {
@@ -527,15 +686,42 @@ public class DatabaseObjectsIO implements IObjectsIO {
}
}
- Field[] getFields(T obj) {
+ public Field[] getFields(T obj) {
+ lock.lock();
+ try {
+ return getFields_(obj);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private Field[] getFields_(T obj) {
return FieldUtils.getFieldsWithAnnotation(obj.getClass(), DbField.class);
}
- Field[] getPrimitiveFields(T obj) {
+ public Field[] getPrimitiveFields(T obj) {
+ lock.lock();
+ try {
+ return getPrimitiveFields_(obj);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private Field[] getPrimitiveFields_(T obj) {
return FieldUtils.getFieldsWithAnnotation(obj.getClass(), DbPrimitiveField.class);
}
- int getBiggestFieldId(Field[] unorderedFields) {
+ public int getBiggestFieldId(Field[] unorderedFields) {
+ lock.lock();
+ try {
+ return getBiggestFieldId_(unorderedFields);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private int getBiggestFieldId_(Field[] unorderedFields) {
int biggestFieldId = -1;
for (Field field : unorderedFields) {
DbField fieldAnnotation = field.getAnnotation(DbField.class);
@@ -547,7 +733,16 @@ public class DatabaseObjectsIO implements IObjectsIO {
return biggestFieldId;
}
- int getBiggestPrimitiveFieldId(Field[] unorderedFields) {
+ public int getBiggestPrimitiveFieldId(Field[] unorderedFields) {
+ lock.lock();
+ try {
+ return getBiggestPrimitiveFieldId_(unorderedFields);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private int getBiggestPrimitiveFieldId_(Field[] unorderedFields) {
int biggestFieldId = -1;
for (Field field : unorderedFields) {
DbPrimitiveField fieldAnnotation = field.getAnnotation(DbPrimitiveField.class);
@@ -572,8 +767,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
}
}
- private T preloadEnhancedObject(Class objectType, int serializedVersion,
- long nativeFieldsRef, long[] fieldRefs, long[] methodRefs) throws IOException {
+ private T preloadEnhancedObject(Class objectType, int serializedVersion, long nativeFieldsRef, long[] fieldRefs, long[] methodRefs) throws IOException {
// Instantiate the class to an object
T obj = toInstance(objectType);
@@ -601,7 +795,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
public long[] allocateNewUIDs(int quantity) throws IOException {
long[] ids = new long[quantity];
for (int i = 0; i < quantity; i++) {
- ids[i] = newNullObject();
+ ids[i] = newNullObject_();
}
return ids;
}
diff --git a/src/main/java/it/cavallium/strangedb/java/database/IObjectsIO.java b/src/main/java/it/cavallium/strangedb/java/database/IObjectsIO.java
index b5f7504..542a1a8 100644
--- a/src/main/java/it/cavallium/strangedb/java/database/IObjectsIO.java
+++ b/src/main/java/it/cavallium/strangedb/java/database/IObjectsIO.java
@@ -2,6 +2,7 @@ package it.cavallium.strangedb.java.database;
import it.cavallium.strangedb.java.objects.EnhancedObject;
import it.cavallium.strangedb.java.annotations.DbDataType;
+import it.cavallium.strangedb.java.objects.EnhancedObjectIndices;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongList;
@@ -9,7 +10,10 @@ import java.io.IOException;
import java.lang.reflect.Method;
public interface IObjectsIO {
- T loadEnhancedObject(long reference, Class objectType) throws IOException;
+ @SuppressWarnings("unchecked")
+ T loadEnhancedObject(long reference) throws IOException;
+
+ EnhancedObjectIndices loadEnhancedObjectUids(long reference) throws IOException;
T loadObject(long reference) throws IOException;
@@ -47,7 +51,7 @@ public interface IObjectsIO {
return reference;
}
- void loadProperty(EnhancedObject enhancedObject, int propertyId, Method propertyGetter, DbDataType propertyType, long propertyUID) throws IOException;
+ void loadProperty(EnhancedObject enhancedObject, int propertyId, DbDataType propertyType, long propertyUID) throws IOException;
void registerClass(Class> type, int id);
diff --git a/src/main/java/it/cavallium/strangedb/java/objects/EnhancedObject.java b/src/main/java/it/cavallium/strangedb/java/objects/EnhancedObject.java
index 07b4b1f..7de5882 100644
--- a/src/main/java/it/cavallium/strangedb/java/objects/EnhancedObject.java
+++ b/src/main/java/it/cavallium/strangedb/java/objects/EnhancedObject.java
@@ -1,18 +1,16 @@
package it.cavallium.strangedb.java.objects;
+import it.cavallium.strangedb.java.annotations.*;
import it.cavallium.strangedb.java.database.IDatabaseTools;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.reflect.MethodUtils;
-import it.cavallium.strangedb.java.annotations.DbClass;
-import it.cavallium.strangedb.java.annotations.DbDataType;
-import it.cavallium.strangedb.java.annotations.DbPrimitiveType;
-import it.cavallium.strangedb.java.annotations.DbPropertyGetter;
-import it.cavallium.strangedb.java.annotations.DbPropertySetter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
public abstract class EnhancedObject {
protected final int version;
@@ -29,8 +27,8 @@ public abstract class EnhancedObject {
private long[] propertyReferences;
private boolean[] loadedProperties;
private Object[] loadedPropertyValues;
- private Map setterMethods;
- private Map getterMethods;
+ private Map setterMethods;
+ private Map getterMethods;
public EnhancedObject() {
version = getClassVersion();
@@ -62,7 +60,7 @@ public abstract class EnhancedObject {
return MethodUtils.getMethodsWithAnnotation(this.getClass(), DbPropertySetter.class);
}
- public void setProperties(Method[] propertyGetters, Method[] propertySetters, DbDataType[] propertyTypes, long[] propertyReferences, Map setterMethods, Map getterMethods) {
+ public void setProperties(Method[] propertyGetters, Method[] propertySetters, DbDataType[] propertyTypes, long[] propertyReferences, Map setterMethods, Map getterMethods) {
this.propertyGetters = propertyGetters;
this.propertySetters = propertySetters;
this.propertyTypes = propertyTypes;
@@ -82,7 +80,7 @@ public abstract class EnhancedObject {
StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
StackWalker.StackFrame stackFrame = walker.walk(f -> f.skip(1).findFirst().orElse(null));
try {
- int propertyId = stackFrame.getDeclaringClass().getDeclaredMethod(stackFrame.getMethodName()).getAnnotation(DbPropertyGetter.class).id();
+ int propertyId = stackFrame.getDeclaringClass().getDeclaredMethod(stackFrame.getMethodName()).getAnnotation(DbProperty.class).id();
return getProperty(propertyId);
} catch (IOException | NoSuchMethodException e) {
throw new RuntimeException(e);
@@ -90,10 +88,10 @@ public abstract class EnhancedObject {
}
@SuppressWarnings("unchecked")
- private T getProperty(int propertyId) throws IOException {
+ public T getProperty(int propertyId) throws IOException {
if (!loadedProperties[propertyId]) {
long propertyUID = propertyReferences[propertyId];
- databaseTools.getObjectsIO().loadProperty(this, propertyId, propertyGetters[propertyId], propertyTypes[propertyId], propertyUID);
+ databaseTools.getObjectsIO().loadProperty(this, propertyId, propertyTypes[propertyId], propertyUID);
}
return (T) loadedPropertyValues[propertyId];
}
@@ -101,7 +99,7 @@ public abstract class EnhancedObject {
public void setProperty(T value) {
StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
StackWalker.StackFrame stackFrame = walker.walk(f -> f.skip(1).findFirst().orElse(null));
- DbPropertySetter propertyAnnotation = setterMethods.get(stackFrame.getMethodName());
+ DbProperty propertyAnnotation = setterMethods.get(stackFrame.getMethodName());
setProperty(propertyAnnotation.id(), value);
}
diff --git a/src/main/java/it/cavallium/strangedb/java/objects/EnhancedObjectIndices.java b/src/main/java/it/cavallium/strangedb/java/objects/EnhancedObjectIndices.java
new file mode 100644
index 0000000..2553acc
--- /dev/null
+++ b/src/main/java/it/cavallium/strangedb/java/objects/EnhancedObjectIndices.java
@@ -0,0 +1,17 @@
+package it.cavallium.strangedb.java.objects;
+
+public class EnhancedObjectIndices {
+ public final long objectUid;
+ public final long[] fieldUids;
+ public final long[] propertyUids;
+ public final long nativeDataUid;
+ public final Class extends EnhancedObject> type;
+
+ public EnhancedObjectIndices(Class extends EnhancedObject> type, long objectUid, long[] fieldUids, long[] propertyUids, long nativeDataUid) {
+ this.type = type;
+ this.objectUid = objectUid;
+ this.fieldUids = fieldUids;
+ this.propertyUids = propertyUids;
+ this.nativeDataUid = nativeDataUid;
+ }
+}
diff --git a/src/main/java/it/cavallium/strangedb/java/objects/EnhancedObjectUpgrader.java b/src/main/java/it/cavallium/strangedb/java/objects/EnhancedObjectUpgrader.java
index dfa40c7..89c7836 100644
--- a/src/main/java/it/cavallium/strangedb/java/objects/EnhancedObjectUpgrader.java
+++ b/src/main/java/it/cavallium/strangedb/java/objects/EnhancedObjectUpgrader.java
@@ -41,15 +41,7 @@ public interface EnhancedObjectUpgrader {
return getPrimitiveField(id, DbPrimitiveType.DOUBLE);
}
- Object getField(int id, DbDataType type, Supplier> enhancedClassType) throws IOException;
+ Object getField(int id, DbDataType type) throws IOException;
- default Object getField(int id, DbDataType type) throws IOException {
- return getField(id, type, null);
- }
-
- Object getMethod(int id, DbDataType type, Supplier> enhancedClassType) throws IOException;
-
- default Object getMethod(int id, DbDataType type) throws IOException {
- return getField(id, type, null);
- }
+ Object getMethod(int id, DbDataType type) throws IOException;
}
diff --git a/src/main/java/it/cavallium/strangedb/java/objects/lists/ClassPosition.java b/src/main/java/it/cavallium/strangedb/java/objects/lists/ClassPosition.java
new file mode 100644
index 0000000..d9ace17
--- /dev/null
+++ b/src/main/java/it/cavallium/strangedb/java/objects/lists/ClassPosition.java
@@ -0,0 +1,7 @@
+package it.cavallium.strangedb.java.objects.lists;
+
+public enum ClassPosition {
+ PROPERTY,
+ FIELD,
+ PRIMITIVE_FIELD
+}
diff --git a/src/main/java/it/cavallium/strangedb/java/objects/lists/ElementsArrayList.java b/src/main/java/it/cavallium/strangedb/java/objects/lists/ElementsArrayList.java
new file mode 100644
index 0000000..afd22c7
--- /dev/null
+++ b/src/main/java/it/cavallium/strangedb/java/objects/lists/ElementsArrayList.java
@@ -0,0 +1,70 @@
+package it.cavallium.strangedb.java.objects.lists;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public class ElementsArrayList implements ElementsList {
+
+ private final ArrayList list;
+
+ public ElementsArrayList() {
+ this.list = new ArrayList<>();
+ }
+
+ public ElementsArrayList(Collection collection) {
+ this.list = new ArrayList<>(collection);
+ }
+
+ public ElementsArrayList(int initialCapacity) {
+ this.list = new ArrayList<>(initialCapacity);
+ }
+
+ @Override
+ public T get(int index) {
+ return list.get(index);
+ }
+
+ @Override
+ public void add(T value) {
+ list.add(value);
+ }
+
+ @Override
+ public void update(int index, T value) {
+ set(index, value);
+ }
+
+ @Override
+ public void set(int index, T value) {
+ list.set(index, value);
+ }
+
+ @Override
+ public void add(int index, T value) {
+ list.add(index, value);
+ }
+
+ @Override
+ public T getLast() {
+ return list.get(list.size() - 1);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return list.isEmpty();
+ }
+
+ @Override
+ public int size() {
+ return list.size();
+ }
+
+ public boolean contains(Object o) {
+ return list.contains(o);
+ }
+
+ public ArrayList asList() {
+ return list;
+ }
+}
diff --git a/src/main/java/it/cavallium/strangedb/java/objects/lists/ElementsList.java b/src/main/java/it/cavallium/strangedb/java/objects/lists/ElementsList.java
new file mode 100644
index 0000000..1ffcd41
--- /dev/null
+++ b/src/main/java/it/cavallium/strangedb/java/objects/lists/ElementsList.java
@@ -0,0 +1,14 @@
+package it.cavallium.strangedb.java.objects.lists;
+
+import java.io.IOException;
+
+interface ElementsList {
+ T get(int index) throws IOException;
+ void add(T value) throws IOException;
+ void update(int index, T value) throws IOException;
+ void set(int index, T value) throws IOException;
+ void add(int index, T value) throws IOException;
+ T getLast() throws IOException;
+ boolean isEmpty();
+ int size();
+}
diff --git a/src/main/java/it/cavallium/strangedb/java/objects/lists/EnhancedObjectStrangeDbList.java b/src/main/java/it/cavallium/strangedb/java/objects/lists/EnhancedObjectStrangeDbList.java
index e1bb0ce..2637530 100644
--- a/src/main/java/it/cavallium/strangedb/java/objects/lists/EnhancedObjectStrangeDbList.java
+++ b/src/main/java/it/cavallium/strangedb/java/objects/lists/EnhancedObjectStrangeDbList.java
@@ -1,5 +1,7 @@
package it.cavallium.strangedb.java.objects.lists;
+import it.cavallium.strangedb.java.database.IObjectsIO;
+import it.cavallium.strangedb.java.objects.EnhancedObjectIndices;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.cavallium.strangedb.java.objects.EnhancedObject;
import it.cavallium.strangedb.java.database.IDatabaseTools;
@@ -33,11 +35,175 @@ public class EnhancedObjectStrangeDbList extends Stran
@Override
protected T loadItem(long uid) throws IOException {
- return databaseTools.getObjectsIO().loadEnhancedObject(uid, type);
+ return databaseTools.getObjectsIO().loadEnhancedObject(uid);
}
@Override
protected void writeItemToDisk(long uid, T item) throws IOException {
databaseTools.getObjectsIO().setEnhancedObject(uid, item);
}
+
+ public ElementsArrayList queryUids(ListQuery query) throws IOException {
+ ElementsArrayList uids = executeQuery(query, this, databaseTools.getObjectsIO());
+ return uids;
+ }
+
+ public ElementsArrayList query(ListQuery query) throws IOException {
+ ElementsArrayList uids = queryUids(query);
+ ElementsArrayList elements = new ElementsArrayList<>(uids.size());
+ for (int i = 0; i < uids.size(); i++) {
+ T element = databaseTools.getObjectsIO().loadEnhancedObject(uids.get(i).objectUid);
+ elements.add(element);
+ }
+ return elements;
+ }
+
+ private ElementsArrayList executeQuery(ListQuery query, ElementsList> inputList, IObjectsIO dbio) throws IOException {
+ if (query instanceof ListQuery.ListQueryElement) {
+ return executeQueryElement((ListQuery.ListQueryElement) query, inputList, dbio);
+ } else if (query instanceof ListQuery.ListQueryAnd) {
+ ListQuery[] children = ((ListQuery.ListQueryAnd) query).getQueryChildren();
+ ElementsArrayList results = null;
+ for (ListQuery childQuery : children) {
+ results = executeQuery(childQuery, results == null ? inputList : results, dbio);
+ if (results.size() == 0) break;
+ }
+ return results;
+ } else if (query instanceof ListQuery.ListQueryOr) {
+ ListQuery[] children = ((ListQuery.ListQueryOr) query).getQueryChildren();
+ ElementsArrayList results = new ElementsArrayList<>();
+ for (ListQuery childQuery : children) {
+ ElementsArrayList childResults = executeQuery(childQuery, inputList, dbio);
+ int childResultsSize = childResults.size();
+ if (childResultsSize == inputList.size()) {
+ return childResults;
+ }
+ addMissingElements(results, childResults);
+ }
+ return results;
+ } else {
+ throw new RuntimeException("Not implemented!");
+ }
+ }
+
+ static void addMissingElements(ElementsArrayList main, ElementsList elementsToAdd) throws IOException {
+ int elementsSize = elementsToAdd.size();
+ for (int i = 0; i < elementsSize; i++) {
+ EnhancedObjectIndices childResultElement = elementsToAdd.get(i);
+ if (!main.contains(childResultElement)) {
+ main.add(childResultElement);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ static ElementsArrayList toElementsArrayList(ElementsList> elementsList) {
+ if (elementsList instanceof EnhancedObjectStrangeDbList>) {
+ return new ElementsArrayList<>(((EnhancedObjectStrangeDbList) elementsList).getIndices());
+ } else if (elementsList instanceof ElementsArrayList>) {
+ return (ElementsArrayList) elementsList;
+ } else {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private static ElementsArrayList executeQueryElement(ListQuery.ListQueryElement query, ElementsList> inputList, IObjectsIO dbio) throws IOException {
+ ElementsArrayList results = new ElementsArrayList<>();
+ if (inputList instanceof EnhancedObjectStrangeDbList>) {
+ EnhancedObjectStrangeDbList> dbList = ((EnhancedObjectStrangeDbList>) inputList);
+ final int listSize = inputList.size();
+ final LongArrayList indices = dbList.getIndices();
+ for (int i = 0; i < listSize; i++) {
+ Long elementUid = indices.get(i);
+ EnhancedObjectIndices elementUids = dbio.loadEnhancedObjectUids(elementUid); // check if the parent object is the declared type
+ Class> declaredRootType = query.valuePointer.getRootType();
+ Class> obtainedRootType = elementUids.type;
+ if (isInstanceOf(obtainedRootType, declaredRootType)) {
+ Object result = resolveItemFromDb(query.valuePointer, dbio, elementUids);
+ if (query.valueOperation.evaluate(result)) {
+ results.add(elementUids);
+ }
+ } else {
+ //todo: use logging api
+ System.err.println(obtainedRootType.getSimpleName() + " is not instance of " + declaredRootType.getSimpleName());
+ }
+ }
+ } else if (inputList instanceof ElementsArrayList>) {
+ final int listSize = inputList.size();
+ ElementsArrayList elementsUids = ((ElementsArrayList) inputList);
+ for (int i = 0; i < listSize; i++) {
+ EnhancedObjectIndices elementUid = elementsUids.get(i);
+ Object result = resolveItemFromDb(query.valuePointer, dbio, elementUid);
+ if (query.valueOperation.evaluate(result)) {
+ results.add(elementUid);
+ }
+ }
+ }
+ return results;
+ }
+
+ static Object resolveItemFromDb(ValuePointer pointer, IObjectsIO objectsIO, EnhancedObjectIndices element) throws IOException {
+ EnhancedObjectIndices currentElement = element;
+ boolean isLastElement;
+ for (int i = 0; i < pointer.size(); i++) {
+ isLastElement = i >= pointer.size() - 1;
+ ValuePointer currentPointer = pointer.at(i);
+
+ int pathNumber = currentPointer.getPathNumber();
+ ClassPosition valueType = currentPointer.getPathType();
+
+ Object value;
+ switch (valueType) {
+ case FIELD: {
+ if (isLastElement) {
+ //TODO: getBlock field data type. it can be an enhancedObject or an object
+ value = objectsIO.loadObject(currentElement.fieldUids[pathNumber]);
+ } else {
+ value = objectsIO.loadEnhancedObjectUids(currentElement.fieldUids[pathNumber]);
+ }
+ break;
+ }
+ case PRIMITIVE_FIELD: {
+ if (isLastElement) {
+ //TODO: getBlock primitive type
+ value = objectsIO.loadPrimitiveData(currentElement.nativeDataUid).getLong(pathNumber);
+ } else {
+ throw new IllegalArgumentException("You can access to a type field only in the last pointer");
+ }
+ break;
+ }
+ case PROPERTY: {
+ if (isLastElement) {
+ //TODO: getBlock field data type. it can be an enhancedObject or an object
+ value = objectsIO.loadObject(currentElement.fieldUids[pathNumber]);
+ } else {
+ value = objectsIO.loadEnhancedObjectUids(currentElement.propertyUids[pathNumber]);
+ }
+ }
+ default: {
+ throw new IllegalArgumentException("Not implemented");
+ }
+ }
+
+ if (isLastElement) {
+ return value;
+ } else {
+ currentElement = (EnhancedObjectIndices) value;
+
+ // check if the object that we obtained is the declared type
+ Class> declaredType = currentPointer.getAdditionalData();
+ Class> obtainedType = currentElement.type;
+ if (!isInstanceOf(obtainedType, declaredType)) {
+ return null;
+ }
+ }
+ }
+ throw new IOException("The pointer is empty");
+ }
+
+
+ private static boolean isInstanceOf(Class> clazz, Class> obj){
+ return obj.isAssignableFrom(clazz);
+ }
}
diff --git a/src/main/java/it/cavallium/strangedb/java/objects/lists/KMP.java b/src/main/java/it/cavallium/strangedb/java/objects/lists/KMP.java
new file mode 100644
index 0000000..3c41d71
--- /dev/null
+++ b/src/main/java/it/cavallium/strangedb/java/objects/lists/KMP.java
@@ -0,0 +1,58 @@
+package it.cavallium.strangedb.java.objects.lists;
+
+public class KMP {
+ public static int KMP(CharSequence content, CharSequence stringToFind) {
+ int[] failureTable = failureTable(stringToFind);
+
+ int targetPointer = 0; // current char in target string
+ int searchPointer = 0; // current char in search string
+
+ while (searchPointer < content.length()) { // while there is more to search with, keep searching
+ if (content.charAt(searchPointer) == stringToFind.charAt(targetPointer)) { // case 1
+ // found current char in targetPointer in search string
+ targetPointer++;
+ if (targetPointer == stringToFind.length()) { // found all characters
+ int x = stringToFind.length() + 1;
+ return searchPointer - x; // return starting index of found target inside searched string
+ }
+ searchPointer++; // move forward if not found target string
+ } else if (targetPointer > 0) { // case 2
+ // use failureTable to use pointer pointed at nearest location of usable string prefix
+ targetPointer = failureTable[targetPointer];
+ } else { // case 3
+ // targetPointer is pointing at state 0, so restart search with current searchPointer index
+ searchPointer++;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns an int[] that points to last valid string prefix, given target string
+ */
+ public static int[] failureTable(CharSequence target) {
+ int[] table = new int[target.length() + 1];
+ // state 0 and 1 are guarenteed be the prior
+ table[0] = -1;
+ table[1] = 0;
+
+ // the pointers pointing at last failure and current satte
+ int left = 0;
+ int right = 2;
+
+ while (right < table.length) { // RIGHT NEVER MOVES RIGHT UNTIL ASSIGNED A VALID POINTER
+ if (target.charAt(right - 1) == target.charAt(left)) { // when both chars before left and right are equal, link both and move both forward
+ left++;
+ table[right] = left;
+ right++;
+ } else if (left > 0) { // if left isn't at the very beginning, then send left backward
+ // by following the already set pointer to where it is pointing to
+ left = table[left];
+ } else { // left has fallen all the way back to the beginning
+ table[right] = left;
+ right++;
+ }
+ }
+ return table;
+ }
+}
diff --git a/src/main/java/it/cavallium/strangedb/java/objects/lists/ListQuery.java b/src/main/java/it/cavallium/strangedb/java/objects/lists/ListQuery.java
new file mode 100644
index 0000000..e19343d
--- /dev/null
+++ b/src/main/java/it/cavallium/strangedb/java/objects/lists/ListQuery.java
@@ -0,0 +1,105 @@
+package it.cavallium.strangedb.java.objects.lists;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public abstract class ListQuery {
+
+ public static ListQuery create(ValuePointer valuePointer, ValueOperation valueOperation) {
+ return new ListQueryElement(valuePointer, valueOperation);
+ }
+
+ public ListQuery and(ValuePointer valuePointer, ValueOperation operation) {
+ return new ListQueryAnd(this, create(valuePointer, operation));
+ }
+
+ public ListQuery and(ListQuery query) {
+ return new ListQueryAnd(this, query);
+ }
+
+ public ListQuery or(ValuePointer valuePointer, ValueOperation operation) {
+ return new ListQueryOr(this, create(valuePointer, operation));
+ }
+
+ public ListQuery or(ListQuery query) {
+ return new ListQueryOr(this, query);
+ }
+
+ abstract List getQueryElementsRecursively();
+
+ static class ListQueryElement extends ListQuery {
+ public final ValuePointer valuePointer;
+ public final ValueOperation valueOperation;
+
+ private ListQueryElement(ValuePointer valuePointer, ValueOperation valueOperation) {
+ this.valuePointer = valuePointer;
+ this.valueOperation = valueOperation;
+ }
+
+ @Override
+ List getQueryElementsRecursively() {
+ return Collections.singletonList(this);
+ }
+ }
+
+ static class ListQueryCollection extends ListQuery {
+ protected ListQuery[] queries;
+
+ private ListQueryCollection(ListQuery... queries) {
+ this.queries = queries;
+ }
+
+ @Override
+ List getQueryElementsRecursively() {
+ List elements = new ArrayList<>();
+ for (ListQuery query : queries) {
+ elements.addAll(query.getQueryElementsRecursively());
+ }
+ return elements;
+ }
+
+ ListQuery[] getQueryChildren() {
+ return queries.clone();
+ }
+ }
+
+ static class ListQueryAnd extends ListQueryCollection {
+ private ListQueryAnd(ListQuery... queries) {
+ super(queries);
+ }
+
+ @Override
+ public ListQuery and(ListQuery query) {
+ return new ListQueryAnd(append(this.queries, query));
+ }
+
+ @Override
+ public ListQuery and(ValuePointer valuePointer, ValueOperation operation) {
+ return and(create(valuePointer, operation));
+ }
+ }
+
+ static class ListQueryOr extends ListQueryCollection {
+ private ListQueryOr(ListQuery... queries) {
+ super(queries);
+ }
+
+ @Override
+ public ListQuery or(ListQuery query) {
+ return new ListQueryOr(append(this.queries, query));
+ }
+
+ @Override
+ public ListQuery or(ValuePointer valuePointer, ValueOperation operation) {
+ return or(create(valuePointer, operation));
+ }
+ }
+
+ private static T[] append(T[] array, T value) {
+ T[] newArray = Arrays.copyOf(array, array.length + 1);
+ newArray[array.length] = value;
+ return newArray;
+ }
+}
diff --git a/src/main/java/it/cavallium/strangedb/java/objects/lists/ObjectStrangeDbList.java b/src/main/java/it/cavallium/strangedb/java/objects/lists/ObjectStrangeDbList.java
index 0bd76c8..fc3f489 100644
--- a/src/main/java/it/cavallium/strangedb/java/objects/lists/ObjectStrangeDbList.java
+++ b/src/main/java/it/cavallium/strangedb/java/objects/lists/ObjectStrangeDbList.java
@@ -17,7 +17,7 @@ public class ObjectStrangeDbList extends StrangeDbList {
return indices;
}
- protected ObjectStrangeDbList() {
+ public ObjectStrangeDbList() {
super();
}
diff --git a/src/main/java/it/cavallium/strangedb/java/objects/lists/StrangeDbList.java b/src/main/java/it/cavallium/strangedb/java/objects/lists/StrangeDbList.java
index 05696aa..1d4f9e6 100644
--- a/src/main/java/it/cavallium/strangedb/java/objects/lists/StrangeDbList.java
+++ b/src/main/java/it/cavallium/strangedb/java/objects/lists/StrangeDbList.java
@@ -5,10 +5,9 @@ import it.cavallium.strangedb.java.objects.EnhancedObject;
import it.cavallium.strangedb.java.database.IDatabaseTools;
import java.io.IOException;
-import java.util.Collection;
import java.util.StringJoiner;
-public abstract class StrangeDbList extends EnhancedObject {
+public abstract class StrangeDbList extends EnhancedObject implements ElementsList {
private final Object indicesAccessLock = new Object();
@@ -22,6 +21,7 @@ public abstract class StrangeDbList extends EnhancedObject {
super(databaseTools);
}
+ @Override
public T get(int index) throws IOException {
synchronized (indicesAccessLock) {
long uid = getIndices().getLong(index);
@@ -29,6 +29,7 @@ public abstract class StrangeDbList extends EnhancedObject {
}
}
+ @Override
public void add(T value) throws IOException {
long uid = databaseTools.getObjectsIO().newNullObject();
synchronized (indicesAccessLock) {
@@ -37,13 +38,12 @@ public abstract class StrangeDbList extends EnhancedObject {
}
}
+ @Override
public void update(int index, T value) throws IOException {
- synchronized (indicesAccessLock) {
- long uid = getIndices().getLong(index);
- writeItemToDisk(uid, value);
- }
+ set(index, value);
}
+ @Override
public void set(int index, T value) throws IOException {
long uid = databaseTools.getObjectsIO().newNullObject();
synchronized (indicesAccessLock) {
@@ -52,6 +52,7 @@ public abstract class StrangeDbList extends EnhancedObject {
}
}
+ @Override
public void add(int index, T value) throws IOException {
long uid = databaseTools.getObjectsIO().newNullObject();
synchronized (indicesAccessLock) {
@@ -88,7 +89,7 @@ public abstract class StrangeDbList extends EnhancedObject {
@Override
public String toString() {
- return new StringJoiner(", ", StrangeDbList.class.getSimpleName() + "[", "]")
+ return new StringJoiner(", ", StrangeDbList.class.getSimpleName() + "[", "]")
.add(getIndices().size() + " items")
.toString();
}
diff --git a/src/main/java/it/cavallium/strangedb/java/objects/lists/ValueOperation.java b/src/main/java/it/cavallium/strangedb/java/objects/lists/ValueOperation.java
new file mode 100644
index 0000000..9675c3a
--- /dev/null
+++ b/src/main/java/it/cavallium/strangedb/java/objects/lists/ValueOperation.java
@@ -0,0 +1,5 @@
+package it.cavallium.strangedb.java.objects.lists;
+
+public interface ValueOperation {
+ public boolean evaluate(Object value);
+}
diff --git a/src/main/java/it/cavallium/strangedb/java/objects/lists/ValuePointer.java b/src/main/java/it/cavallium/strangedb/java/objects/lists/ValuePointer.java
new file mode 100644
index 0000000..0e6723f
--- /dev/null
+++ b/src/main/java/it/cavallium/strangedb/java/objects/lists/ValuePointer.java
@@ -0,0 +1,182 @@
+package it.cavallium.strangedb.java.objects.lists;
+
+import it.cavallium.strangedb.java.annotations.DbField;
+import it.cavallium.strangedb.java.annotations.DbPrimitiveField;
+import it.cavallium.strangedb.java.annotations.DbProperty;
+import it.cavallium.strangedb.java.objects.EnhancedObject;
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.commons.lang3.reflect.MethodUtils;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+public class ValuePointer {
+
+ private static ValuePointer base = new ValuePointer(new int[0], new ClassPosition[0], new Object[0], null);
+
+ private final int[] pathNumbers;
+ private final ClassPosition[] pathTypes;
+ /**
+ * PropertyType
+ */
+ private final Object[] additionalData;
+ /**
+ * ParentType
+ */
+ private final Class> rootType;
+
+ private ValuePointer(int[] pathNumbers, ClassPosition[] pathTypes, Object[] additionalData, Class> rootType) {
+ this.pathNumbers = pathNumbers;
+ this.pathTypes = pathTypes;
+ this.additionalData = additionalData;
+ this.rootType = rootType;
+ }
+
+ public static ValuePointer ofField(Class parentType, String field) {
+ return base.field(parentType, field);
+ }
+
+ public static ValuePointer ofProp(Class parentType, String property) {
+ return base.prop(parentType, property);
+ }
+ public static ValuePointer ofPrimitiveField(Class parentType, String primitiveFieldName) {
+ return base.primitiveField(parentType, primitiveFieldName);
+ }
+
+ public ValuePointer prop(Class parentType, String propertyName) {
+
+ ClassPosition[] newPathTypes = append(this.pathTypes, ClassPosition.FIELD);
+
+ Method[] methods = MethodUtils.getMethodsWithAnnotation(parentType, DbProperty.class);
+ DbProperty dbProperty = null;
+ Class> propType = null;
+ for (Method method : methods) {
+ DbProperty annotation = method.getAnnotation(DbProperty.class);
+ if (annotation.name().equals(propertyName)) {
+ propType = method.getReturnType();
+ dbProperty = annotation;
+ break;
+ }
+ }
+ if (dbProperty == null) {
+ throw new IllegalArgumentException("Property '" + propertyName + "' not found in class " + parentType.getSimpleName());
+ }
+
+ int[] newPathNumbers = append(this.pathNumbers, dbProperty.id());
+ Object[] newAdditionalData = append(this.additionalData, propType);
+ Class> rootType = this.rootType == null ? parentType : this.rootType;
+ if (newAdditionalData.length > 1) {
+ newAdditionalData[newAdditionalData.length - 2] = parentType;
+ }
+ return new ValuePointer(newPathNumbers, newPathTypes, newAdditionalData, rootType);
+ }
+
+ public ValuePointer field(Class parentType, String fieldName) {
+ ClassPosition[] newPathTypes = append(this.pathTypes, ClassPosition.FIELD);
+
+ Field[] fields = FieldUtils.getFieldsWithAnnotation(parentType, DbField.class);
+ DbField dbField = null;
+ Class> fieldType = null;
+ for (Field field : fields) {
+ DbField annotation = field.getAnnotation(DbField.class);
+ if (annotation.name().equals(fieldName)) {
+ fieldType = field.getType();
+ dbField = annotation;
+ break;
+ }
+ }
+ if (dbField == null) {
+ throw new IllegalArgumentException("Field '" + fieldName + "' not found in class " + parentType.getSimpleName());
+ }
+
+ int[] newPathNumbers = append(this.pathNumbers, dbField.id());
+ Object[] newAdditionalData = append(this.additionalData, fieldType);
+ if (newAdditionalData.length > 1) {
+ newAdditionalData[newAdditionalData.length - 2] = parentType;
+ }
+ Class> rootType = this.rootType == null ? parentType : this.rootType;
+ return new ValuePointer(newPathNumbers, newPathTypes, newAdditionalData, rootType);
+ }
+
+ public ValuePointer primitiveField(Class parentType, String primitiveFieldName) {
+ ClassPosition[] newPathTypes = append(this.pathTypes, ClassPosition.PRIMITIVE_FIELD);
+
+ Field[] fields = FieldUtils.getFieldsWithAnnotation(parentType, DbPrimitiveField.class);
+ DbPrimitiveField dbField = null;
+ Class> fieldType = null;
+ for (Field field : fields) {
+ DbPrimitiveField annotation = field.getAnnotation(DbPrimitiveField.class);
+ if (annotation.name().equals(primitiveFieldName)) {
+ fieldType = field.getType();
+ dbField = annotation;
+ break;
+ }
+ }
+ if (dbField == null) {
+ throw new IllegalArgumentException("Field '" + primitiveFieldName + "' not found in class " + parentType.getSimpleName());
+ }
+
+ int[] newPathNumbers = append(this.pathNumbers, dbField.id());
+ Object[] newAdditionalData = append(this.additionalData, fieldType);
+ if (newAdditionalData.length > 1) {
+ newAdditionalData[newAdditionalData.length - 2] = parentType;
+ }
+ Class> rootType = this.rootType == null ? parentType : this.rootType;
+ return new ValuePointer(newPathNumbers, newPathTypes, newAdditionalData, rootType);
+ }
+
+ public ValuePointer at(int index) {
+ if (index >= pathNumbers.length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ if (index == pathNumbers.length - 1) {
+ return this;
+ }
+ return new ValuePointer(Arrays.copyOf(this.pathNumbers, index + 1),
+ Arrays.copyOf(this.pathTypes, index + 1),
+ Arrays.copyOf(this.additionalData, index + 1),
+ rootType);
+ }
+
+ public int size() {
+ return this.pathNumbers.length;
+ }
+
+ public boolean hasPrevious() {
+ return pathNumbers.length > 0;
+ }
+
+ public ValuePointer previous() {
+ return at(pathNumbers.length - 2);
+ }
+
+ private static int[] append(int[] array, int value) {
+ int[] newArray = Arrays.copyOf(array, array.length + 1);
+ newArray[array.length] = value;
+ return newArray;
+ }
+
+ private static T[] append(T[] array, T value) {
+ T[] newArray = Arrays.copyOf(array, array.length + 1);
+ newArray[array.length] = value;
+ return newArray;
+ }
+
+ public int getPathNumber() {
+ return pathNumbers[pathNumbers.length - 1];
+ }
+
+ public ClassPosition getPathType() {
+ return pathTypes[pathTypes.length - 1];
+ }
+
+ @SuppressWarnings("unchecked")
+ public T getAdditionalData() {
+ return (T) additionalData[additionalData.length - 1];
+ }
+
+ public Class> getRootType() {
+ return rootType;
+ }
+}
diff --git a/src/main/java/it/cavallium/strangedb/java/objects/lists/operations/Contains.java b/src/main/java/it/cavallium/strangedb/java/objects/lists/operations/Contains.java
new file mode 100644
index 0000000..b40f556
--- /dev/null
+++ b/src/main/java/it/cavallium/strangedb/java/objects/lists/operations/Contains.java
@@ -0,0 +1,25 @@
+package it.cavallium.strangedb.java.objects.lists.operations;
+
+import it.cavallium.strangedb.java.objects.lists.KMP;
+import it.cavallium.strangedb.java.objects.lists.ValueOperation;
+
+public class Contains implements ValueOperation {
+
+ private final T containsValue;
+
+ private Contains(T containsValue) {
+ this.containsValue = containsValue;
+ }
+
+ public static Contains containsValue(T value) {
+ return new Contains(value);
+ }
+
+ @Override
+ public boolean evaluate(Object value) {
+ if (value instanceof CharSequence) {
+ return KMP.KMP((CharSequence) value, containsValue) != -1;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/it/cavallium/strangedb/java/objects/lists/operations/ContainsIgnoreCase.java b/src/main/java/it/cavallium/strangedb/java/objects/lists/operations/ContainsIgnoreCase.java
new file mode 100644
index 0000000..8594775
--- /dev/null
+++ b/src/main/java/it/cavallium/strangedb/java/objects/lists/operations/ContainsIgnoreCase.java
@@ -0,0 +1,25 @@
+package it.cavallium.strangedb.java.objects.lists.operations;
+
+import it.cavallium.strangedb.java.objects.lists.KMP;
+import it.cavallium.strangedb.java.objects.lists.ValueOperation;
+
+public class ContainsIgnoreCase implements ValueOperation {
+
+ private final String containsValue;
+
+ private ContainsIgnoreCase(String containsValue) {
+ this.containsValue = containsValue.toLowerCase();
+ }
+
+ public static ContainsIgnoreCase containsValue(String value) {
+ return new ContainsIgnoreCase(value);
+ }
+
+ @Override
+ public boolean evaluate(Object value) {
+ if (value instanceof String) {
+ return KMP.KMP(((String) value).toLowerCase(), containsValue) != -1;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/it/cavallium/strangedb/java/objects/lists/operations/Equals.java b/src/main/java/it/cavallium/strangedb/java/objects/lists/operations/Equals.java
new file mode 100644
index 0000000..a8e5c1b
--- /dev/null
+++ b/src/main/java/it/cavallium/strangedb/java/objects/lists/operations/Equals.java
@@ -0,0 +1,21 @@
+package it.cavallium.strangedb.java.objects.lists.operations;
+
+import it.cavallium.strangedb.java.objects.lists.ValueOperation;
+
+public class Equals implements ValueOperation {
+
+ private final T equalToValue;
+
+ private Equals(T equalToValue) {
+ this.equalToValue = equalToValue;
+ }
+
+ public static Equals to(T value) {
+ return new Equals(value);
+ }
+
+ @Override
+ public boolean evaluate(Object value) {
+ return equalToValue.equals(value);
+ }
+}
diff --git a/src/test/java/it/cavallium/strangedb/tests/Clean.java b/src/test/java/it/cavallium/strangedb/tests/Clean.java
index fc32e0d..bd0a977 100644
--- a/src/test/java/it/cavallium/strangedb/tests/Clean.java
+++ b/src/test/java/it/cavallium/strangedb/tests/Clean.java
@@ -1,14 +1,11 @@
package it.cavallium.strangedb.tests;
+import it.cavallium.strangedb.java.annotations.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import it.cavallium.strangedb.java.objects.EnhancedObject;
import it.cavallium.strangedb.java.database.IDatabaseTools;
-import it.cavallium.strangedb.java.annotations.DbDataType;
-import it.cavallium.strangedb.java.annotations.DbField;
-import it.cavallium.strangedb.java.annotations.DbPropertyGetter;
-import it.cavallium.strangedb.java.annotations.DbPropertySetter;
import it.cavallium.strangedb.utils.NTestUtils;
import java.io.IOException;
@@ -20,7 +17,7 @@ public class Clean {
@Before
public void setUp() throws Exception {
db = NTestUtils.wrapDb().create((db) -> {
- root = db.get().loadRoot(RootTwoClasses.class, RootTwoClasses::new);
+ root = db.get().loadRoot(RootTwoClasses::new);
});
root.class1 = new NTestUtils.RootClass(db.get());
db.setRootClassValues(root.class1);
@@ -40,7 +37,7 @@ public class Clean {
db.testRootClassValues(root.getClass4());
db.get().closeAndClean();
db = NTestUtils.wrapDb().create((db) -> {
- root = db.get().loadRoot(RootTwoClasses.class, RootTwoClasses::new);
+ root = db.get().loadRoot(RootTwoClasses::new);
});
}
@@ -65,22 +62,26 @@ public class Clean {
super(databaseTools);
}
- @DbPropertyGetter(id = 0, type = DbDataType.ENHANCED_OBJECT)
+ @DbProperty(id = 0, type = DbDataType.ENHANCED_OBJECT)
+ @DbPropertyGetter
public NTestUtils.RootClass getClass3() {
return getProperty();
}
- @DbPropertySetter(id = 0, type = DbDataType.ENHANCED_OBJECT)
+ @DbProperty(id = 0, type = DbDataType.ENHANCED_OBJECT)
+ @DbPropertySetter
public void setClass3(NTestUtils.RootClass value) {
setProperty(value);
}
- @DbPropertyGetter(id = 1, type = DbDataType.ENHANCED_OBJECT)
+ @DbProperty(id = 1, type = DbDataType.ENHANCED_OBJECT)
+ @DbPropertyGetter
public NTestUtils.RootClass getClass4() {
return getProperty();
}
- @DbPropertySetter(id = 1, type = DbDataType.ENHANCED_OBJECT)
+ @DbProperty(id = 1, type = DbDataType.ENHANCED_OBJECT)
+ @DbPropertySetter
public void setClass4(NTestUtils.RootClass value) {
setProperty(value);
}
diff --git a/src/test/java/it/cavallium/strangedb/tests/EnhancedClassUpdate.java b/src/test/java/it/cavallium/strangedb/tests/EnhancedClassUpdate.java
index 2416e48..bb6b272 100644
--- a/src/test/java/it/cavallium/strangedb/tests/EnhancedClassUpdate.java
+++ b/src/test/java/it/cavallium/strangedb/tests/EnhancedClassUpdate.java
@@ -25,7 +25,7 @@ public class EnhancedClassUpdate {
path2 = Files.createTempFile("db-tests-blocks-", ".db");
path3 = Files.createTempFile("db-tests-references-", ".db");
db = new DatabaseJava(path1, path2, path3);
- OldClass root = db.loadRoot(OldClass.class, OldClass::new);
+ OldClass root = db.loadRoot(OldClass::new);
root.field1 = "Abc";
root.field2 = 12;
root.field4 = 13;
@@ -35,7 +35,7 @@ public class EnhancedClassUpdate {
@Test
public void shouldUpdateClass() throws IOException {
db = new DatabaseJava(path1, path2, path3);
- V2Class root = db.loadRoot(V2Class.class, V2Class::new);
+ V2Class root = db.loadRoot(V2Class::new);
assertEquals(root.field4, "Abc");
assertEquals(root.field2, 12);
assertEquals(root.field1, 13L);
diff --git a/src/test/java/it/cavallium/strangedb/tests/ListContainer.java b/src/test/java/it/cavallium/strangedb/tests/ListContainer.java
new file mode 100644
index 0000000..ad27ca7
--- /dev/null
+++ b/src/test/java/it/cavallium/strangedb/tests/ListContainer.java
@@ -0,0 +1,44 @@
+package it.cavallium.strangedb.tests;
+
+import it.cavallium.strangedb.java.annotations.DbDataType;
+import it.cavallium.strangedb.java.annotations.DbField;
+import it.cavallium.strangedb.java.database.IDatabaseTools;
+import it.cavallium.strangedb.java.objects.EnhancedObject;
+import it.cavallium.strangedb.java.objects.lists.EnhancedObjectStrangeDbList;
+
+import java.io.IOException;
+import java.util.Random;
+
+public class ListContainer extends EnhancedObject {
+
+ @DbField(id = 0, type = DbDataType.ENHANCED_OBJECT)
+ public EnhancedObjectStrangeDbList usersList;
+
+ public ListContainer() {
+ }
+
+ public ListContainer(IDatabaseTools databaseTools, int count) throws IOException {
+ super(databaseTools);
+ this.usersList = new EnhancedObjectStrangeDbList<>(databaseTools, User.class);
+ Random random = new Random();
+ for (int i = 0; i < count; i++) {
+ User usr;
+ int randomInt = random.nextInt(2);
+ switch (randomInt) {
+ case 0:
+ usr = new User(databaseTools, "Rossi" + count + "Mario"+count, "the" + count + "_mariorossi99", "Long long big " + count + " giant bio mario rossi 99 abcdefghijklmnopqrstuvwxyz");
+ break;
+ case 1:
+ usr = new User(databaseTools, QueryTests.constantFirstName, QueryTests.constantUsername, QueryTests.constantBio);
+ break;
+ case 2:
+ usr = new User(databaseTools, QueryTests.constantFirstName, "b" + count + "a", QueryTests.constantBio);
+ break;
+ default:
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ this.usersList.add(usr);
+ }
+ }
+
+}
diff --git a/src/test/java/it/cavallium/strangedb/tests/MultipleEnhancedObjects.java b/src/test/java/it/cavallium/strangedb/tests/MultipleEnhancedObjects.java
index 23cd1db..d6177d7 100644
--- a/src/test/java/it/cavallium/strangedb/tests/MultipleEnhancedObjects.java
+++ b/src/test/java/it/cavallium/strangedb/tests/MultipleEnhancedObjects.java
@@ -1,10 +1,7 @@
package it.cavallium.strangedb.tests;
+import it.cavallium.strangedb.java.annotations.*;
import it.cavallium.strangedb.java.objects.EnhancedObject;
-import it.cavallium.strangedb.java.annotations.DbDataType;
-import it.cavallium.strangedb.java.annotations.DbField;
-import it.cavallium.strangedb.java.annotations.DbPropertyGetter;
-import it.cavallium.strangedb.java.annotations.DbPropertySetter;
import it.cavallium.strangedb.java.database.IDatabaseTools;
import it.cavallium.strangedb.utils.NTestUtils;
import org.junit.After;
@@ -20,7 +17,7 @@ public class MultipleEnhancedObjects {
@Before
public void setUp() throws Exception {
db = NTestUtils.wrapDb().create((db) -> {
- root = db.get().loadRoot(RootTwoClasses.class, RootTwoClasses::new);
+ root = db.get().loadRoot(RootTwoClasses::new);
});
root.class1 = new NTestUtils.RootClass(db.get());
db.setRootClassValues(root.class1);
@@ -62,22 +59,26 @@ public class MultipleEnhancedObjects {
super(databaseTools);
}
- @DbPropertyGetter(id = 0, type = DbDataType.ENHANCED_OBJECT)
+ @DbProperty(id = 0, type = DbDataType.ENHANCED_OBJECT)
+ @DbPropertyGetter
public NTestUtils.RootClass getClass3() {
return getProperty();
}
- @DbPropertySetter(id = 0, type = DbDataType.ENHANCED_OBJECT)
+ @DbProperty(id = 0, type = DbDataType.ENHANCED_OBJECT)
+ @DbPropertySetter
public void setClass3(NTestUtils.RootClass value) {
setProperty(value);
}
- @DbPropertyGetter(id = 1, type = DbDataType.ENHANCED_OBJECT)
+ @DbProperty(id = 1, type = DbDataType.ENHANCED_OBJECT)
+ @DbPropertyGetter
public NTestUtils.RootClass getClass4() {
return getProperty();
}
- @DbPropertySetter(id = 1, type = DbDataType.ENHANCED_OBJECT)
+ @DbProperty(id = 1, type = DbDataType.ENHANCED_OBJECT)
+ @DbPropertySetter
public void setClass4(NTestUtils.RootClass value) {
setProperty(value);
}
diff --git a/src/test/java/it/cavallium/strangedb/tests/ObjectListTests.java b/src/test/java/it/cavallium/strangedb/tests/ObjectListTests.java
new file mode 100644
index 0000000..784337e
--- /dev/null
+++ b/src/test/java/it/cavallium/strangedb/tests/ObjectListTests.java
@@ -0,0 +1,139 @@
+package it.cavallium.strangedb.tests;
+
+import it.cavallium.strangedb.java.annotations.DbDataType;
+import it.cavallium.strangedb.java.annotations.DbField;
+import it.cavallium.strangedb.java.database.DatabaseJava;
+import it.cavallium.strangedb.java.database.IDatabaseTools;
+import it.cavallium.strangedb.java.objects.EnhancedObject;
+import it.cavallium.strangedb.java.objects.lists.EnhancedObjectStrangeDbList;
+import it.cavallium.strangedb.java.objects.lists.ObjectStrangeDbList;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import static org.junit.Assert.assertEquals;
+
+public class ObjectListTests {
+
+ private Path path1;
+ private Path path2;
+ private Path path3;
+ private DatabaseJava db;
+
+ @Before
+ public void setUp() throws Exception {
+ path1 = Files.createTempFile("db-tests-data-", ".db");
+ path2 = Files.createTempFile("db-tests-blocks-", ".db");
+ path3 = Files.createTempFile("db-tests-references-", ".db");
+ db = new DatabaseJava(path1, path2, path3);
+ ListsRoot root = db.loadRoot(ListsRoot::new);
+ for (int i = 0; i < 5000; i++) {
+ root.objectList.add(new ObjectItem(i));
+ root.enhancedObjectList.add(new EnhancedObjectItem(db, i));
+ }
+ for (int i = 0; i < 5000; i++) {
+ if (i % 10 == 0) {
+ root.objectList.update(i, new ObjectItem(i));
+ root.enhancedObjectList.update(i, new EnhancedObjectItem(db, i));
+ }
+ }
+ for (int i = 0; i < 5000; i++) {
+ if (i % 11 == 0) {
+ root.objectList.set(i, new ObjectItem(i));
+ root.enhancedObjectList.set(i, new EnhancedObjectItem(db, i));
+ }
+ }
+ for (int i = 5000; i < 6000; i++) {
+ root.objectList.add(new ObjectItem(0));
+ root.enhancedObjectList.add(i, new EnhancedObjectItem(db, 0));
+ }
+ db.close();
+ }
+
+ @Test
+ public void shouldUpdateClass() throws IOException {
+ db = new DatabaseJava(path1, path2, path3);
+ ListsRoot root = db.loadRoot(ListsRoot::new);
+
+ new Thread(() -> {
+ try {
+ for (int i = 0; i < 5000; i++) {
+ String val = root.objectList.get(i).value;
+ assertEquals(val, "test_" + i);
+ val = root.enhancedObjectList.get(i).value;
+ assertEquals(val, "test_" + i);
+ }
+ for (int i = 5000; i < 6000; i++) {
+ assertEquals(root.objectList.get(i).value, "test_" + 0);
+ assertEquals(root.enhancedObjectList.get(i).value, "test_" + 0);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }).start();
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ db.close();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ Files.deleteIfExists(path1);
+ Files.deleteIfExists(path2);
+ Files.deleteIfExists(path3);
+ }
+
+ public static class ListsRoot extends EnhancedObject {
+
+ @DbField(id = 0,name = "objectList", type = DbDataType.ENHANCED_OBJECT)
+ public ObjectStrangeDbList objectList;
+ @DbField(id = 1,name = "enhancedObjectList", type = DbDataType.ENHANCED_OBJECT)
+ public EnhancedObjectStrangeDbList enhancedObjectList;
+
+ @Deprecated
+ public ListsRoot() {
+
+ }
+
+
+ public ListsRoot(IDatabaseTools tools) throws IOException {
+ super(tools);
+ objectList = new ObjectStrangeDbList<>(tools);
+ enhancedObjectList = new EnhancedObjectStrangeDbList<>(tools, EnhancedObjectItem.class);
+ }
+ }
+
+ public static class ObjectItem {
+ private String value;
+
+ public ObjectItem() {
+
+ }
+
+ private ObjectItem(int i) {
+ this.value = "test_" + i;
+ }
+ }
+
+ public static class EnhancedObjectItem extends EnhancedObject {
+ @DbField(id = 0, type = DbDataType.OBJECT, name = "value")
+ private String value;
+
+ @Deprecated
+ public EnhancedObjectItem() {
+
+ }
+
+ public EnhancedObjectItem(IDatabaseTools tools, int i) throws IOException {
+ super(tools);
+ this.value = "test_" + i;
+ }
+ }
+}
diff --git a/src/test/java/it/cavallium/strangedb/tests/Performance.java b/src/test/java/it/cavallium/strangedb/tests/Performance.java
index 2fa5bab..1f82833 100644
--- a/src/test/java/it/cavallium/strangedb/tests/Performance.java
+++ b/src/test/java/it/cavallium/strangedb/tests/Performance.java
@@ -49,16 +49,16 @@ public class Performance {
System.out.println("Test name Total Time | Time at 1 Time at 10 Time at 100 Time at 1K Time at 10K");
System.out.println("-------------------------------------------------------+-----------------------------------------------------------------");
testS("DatabaseCore creation", 3000, Performance::deleteDb, Performance::generateDb, () -> {});
- testS("DatabaseCore root creation", 3000, Performance::regenDb, () -> db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new), () -> {});
+ testS("DatabaseCore root creation", 3000, Performance::regenDb, () -> db.loadRoot(PreloadedListContainer::new), () -> {});
final VariableWrapper preloadedListContainer = new VariableWrapper<>(null);
final VariableWrapper simpleEnhancedObjectContainer = new VariableWrapper<>(null);
testS("ObjectStrangeDbList creation", 3000, () -> {
regenDb();
- preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
+ preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new);
}, () -> preloadedListContainer.var.list = new ObjectStrangeDbList<>(db), () -> {});
testS("ObjectStrangeDbList: Filling with 1000 items", 100, () -> {
regenDb();
- preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
+ preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new);
preloadedListContainer.var.list = new ObjectStrangeDbList<>(db);
}, () -> {
for (int i = 0; i < 1000; i++) {
@@ -67,7 +67,7 @@ public class Performance {
}, () -> {});
testS("ObjectStrangeDbList: Filling with 1000 items", 100, () -> {
regenDb();
- preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
+ preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new);
preloadedListContainer.var.listOfEnhancedObj = new EnhancedObjectStrangeDbList<>(db, SimpleEnhancedObject.class);
simpleEnhancedObjectContainer.var = new SimpleEnhancedObject(db);
simpleEnhancedObjectContainer.var.integerNumber = 10;
@@ -83,7 +83,7 @@ public class Performance {
}, () -> {});
testS("ObjectStrangeDbList: Filling with 10000 items", 10, () -> {
regenDb();
- preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
+ preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new);
preloadedListContainer.var.list = new ObjectStrangeDbList<>(db);
}, () -> {
for (int i = 0; i < 10000; i++) {
@@ -92,7 +92,7 @@ public class Performance {
}, () -> {});
testS("ObjectStrangeDbList: Filling with 100000 items", 1, () -> {
regenDb();
- preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
+ preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new);
preloadedListContainer.var.list = new ObjectStrangeDbList<>(db);
}, () -> {
for (int i = 0; i < 100000; i++) {
@@ -101,7 +101,7 @@ public class Performance {
}, () -> {});
testS("ObjectStrangeDbList: Loading 1000 items", 100, () -> {
regenDb();
- preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
+ preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new);
preloadedListContainer.var.list = new ObjectStrangeDbList<>(db);
for (int i = 0; i < 1000; i++) {
preloadedListContainer.var.list.add(1000);
@@ -113,7 +113,7 @@ public class Performance {
}, () -> {});
testS("ObjectStrangeDbList: Loading with 1000 items", 100, () -> {
regenDb();
- preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
+ preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new);
preloadedListContainer.var.listOfEnhancedObj = new EnhancedObjectStrangeDbList<>(db, SimpleEnhancedObject.class);
simpleEnhancedObjectContainer.var = new SimpleEnhancedObject(db);
simpleEnhancedObjectContainer.var.integerNumber = 10;
@@ -132,7 +132,7 @@ public class Performance {
}, () -> {});
testS("ObjectStrangeDbList: Loading 10000 items", 10, () -> {
regenDb();
- preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
+ preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new);
preloadedListContainer.var.list = new ObjectStrangeDbList<>(db);
for (int i = 0; i < 10000; i++) {
preloadedListContainer.var.list.add(1000);
@@ -144,7 +144,7 @@ public class Performance {
}, () -> {});
testS("ObjectStrangeDbList: getLast() with 1000 items", 100, () -> {
regenDb();
- preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
+ preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new);
preloadedListContainer.var.list = new ObjectStrangeDbList<>(db);
for (int i = 0; i < 1000; i++) {
preloadedListContainer.var.list.add(1000);
@@ -154,7 +154,7 @@ public class Performance {
}, () -> {});
testS("ObjectStrangeDbList: getLast() with 1000 items", 100, () -> {
regenDb();
- preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
+ preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new);
preloadedListContainer.var.listOfEnhancedObj = new EnhancedObjectStrangeDbList<>(db, SimpleEnhancedObject.class);
simpleEnhancedObjectContainer.var = new SimpleEnhancedObject(db);
simpleEnhancedObjectContainer.var.integerNumber = 10;
@@ -171,7 +171,7 @@ public class Performance {
}, () -> {});
testS("ObjectStrangeDbList: size() with 1000 items", 100, () -> {
regenDb();
- preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
+ preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new);
preloadedListContainer.var.list = new ObjectStrangeDbList<>(db);
for (int i = 0; i < 1000; i++) {
preloadedListContainer.var.list.add(1000);
@@ -318,12 +318,14 @@ public class Performance {
}
- @DbPropertyGetter(id = 0, type = DbDataType.ENHANCED_OBJECT)
+ @DbProperty(id = 0, type = DbDataType.ENHANCED_OBJECT)
+ @DbPropertyGetter()
public ObjectStrangeDbList getList() {
return getProperty();
}
- @DbPropertySetter(id = 1, type = DbDataType.ENHANCED_OBJECT)
+ @DbProperty(id = 1, type = DbDataType.ENHANCED_OBJECT)
+ @DbPropertySetter()
public void setList(ObjectStrangeDbList list) {
setProperty(list);
}
diff --git a/src/test/java/it/cavallium/strangedb/tests/QueryTests.java b/src/test/java/it/cavallium/strangedb/tests/QueryTests.java
new file mode 100644
index 0000000..9d4aaad
--- /dev/null
+++ b/src/test/java/it/cavallium/strangedb/tests/QueryTests.java
@@ -0,0 +1,59 @@
+package it.cavallium.strangedb.tests;
+
+import it.cavallium.strangedb.java.database.DatabaseJava;
+import it.cavallium.strangedb.java.objects.lists.ListQuery;
+import it.cavallium.strangedb.java.objects.lists.ValuePointer;
+import it.cavallium.strangedb.java.objects.lists.operations.Equals;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+
+import static org.junit.Assert.assertNotEquals;
+
+public class QueryTests {
+
+ public static final String constantFirstName = "Jesus christ this is a very strange first name";
+ public static final String constantUsername = "is this an username?";
+ public static final String constantBio = "and is this a bio??? Are you mad?";
+ private Path path1;
+ private Path path2;
+ private Path path3;
+ private DatabaseJava db;
+
+ @Before
+ public void setUp() throws Exception {
+ path1 = Files.createTempFile("db-tests-data-", ".db");
+ path2 = Files.createTempFile("db-tests-blocks-", ".db");
+ path3 = Files.createTempFile("db-tests-references-", ".db");
+ db = new DatabaseJava(path1, path2, path3);
+ }
+
+ @Test
+ public void shouldCreateListAndQuery() throws IOException {
+ ListContainer root = db.loadRoot((db) -> new ListContainer(db, 1000));
+ ListQuery query = ListQuery.create(ValuePointer.ofField(User.class, "firstName"), Equals.to(constantFirstName))
+ .and(ValuePointer.ofField(User.class, "username"), Equals.to(constantUsername))
+ .and(ValuePointer.ofField(User.class, "fullInfo").field(UserFullInfo.class, "bio"), Equals.to(constantBio));
+ long time1 = System.currentTimeMillis();
+ ArrayList elements = root.usersList.query(query).asList();
+ System.out.println("Time elapsed: " + (System.currentTimeMillis() - time1));
+ System.out.println("Found " + elements.size() + " elements. First 5 items:");
+ assertNotEquals(elements.size(), 0);
+ for (int i = 0; i < (elements.size() > 10 ? 10 : elements.size()); i++) {
+ System.out.println(elements.get(i));
+ }
+ db.close();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ Files.deleteIfExists(path1);
+ Files.deleteIfExists(path2);
+ Files.deleteIfExists(path3);
+ }
+}
diff --git a/src/test/java/it/cavallium/strangedb/tests/User.java b/src/test/java/it/cavallium/strangedb/tests/User.java
new file mode 100644
index 0000000..202001a
--- /dev/null
+++ b/src/test/java/it/cavallium/strangedb/tests/User.java
@@ -0,0 +1,40 @@
+package it.cavallium.strangedb.tests;
+
+import it.cavallium.strangedb.java.annotations.DbDataType;
+import it.cavallium.strangedb.java.annotations.DbField;
+import it.cavallium.strangedb.java.database.IDatabaseTools;
+import it.cavallium.strangedb.java.objects.EnhancedObject;
+
+import java.io.IOException;
+import java.util.StringJoiner;
+
+public class User extends EnhancedObject {
+
+ @DbField(id = 0, name = "firstName")
+ public String firstName;
+
+ @DbField(id = 1, name = "username")
+ public String username;
+
+ @DbField(id = 2, type = DbDataType.ENHANCED_OBJECT, name = "fullInfo")
+ public UserFullInfo fullInfo;
+
+ public User() {
+ }
+
+ public User(IDatabaseTools databaseTools, String firstName, String username, String bio) throws IOException {
+ super(databaseTools);
+ this.firstName = firstName;
+ this.username = username;
+ this.fullInfo = new UserFullInfo(databaseTools, bio);
+ }
+
+ @Override
+ public String toString() {
+ return new StringJoiner(", ", User.class.getSimpleName() + "[", "]")
+ .add("firstName='" + firstName + "'")
+ .add("username='" + username + "'")
+ .add("fullInfo=" + fullInfo)
+ .toString();
+ }
+}
diff --git a/src/test/java/it/cavallium/strangedb/tests/UserFullInfo.java b/src/test/java/it/cavallium/strangedb/tests/UserFullInfo.java
new file mode 100644
index 0000000..d9fd2bf
--- /dev/null
+++ b/src/test/java/it/cavallium/strangedb/tests/UserFullInfo.java
@@ -0,0 +1,31 @@
+package it.cavallium.strangedb.tests;
+
+import it.cavallium.strangedb.java.annotations.DbDataType;
+import it.cavallium.strangedb.java.annotations.DbField;
+import it.cavallium.strangedb.java.database.IDatabaseTools;
+import it.cavallium.strangedb.java.objects.EnhancedObject;
+
+import java.io.IOException;
+import java.util.StringJoiner;
+
+public class UserFullInfo extends EnhancedObject {
+
+ @DbField(id = 0, name = "bio")
+ public String bio;
+
+ public UserFullInfo() {
+
+ }
+
+ public UserFullInfo(IDatabaseTools databaseTools, String bio) throws IOException {
+ super(databaseTools);
+ this.bio = bio;
+ }
+
+ @Override
+ public String toString() {
+ return new StringJoiner(", ", UserFullInfo.class.getSimpleName() + "[", "]")
+ .add("bio='" + bio + "'")
+ .toString();
+ }
+}
diff --git a/src/test/java/it/cavallium/strangedb/utils/NTestUtils.java b/src/test/java/it/cavallium/strangedb/utils/NTestUtils.java
index e79be44..f34246b 100644
--- a/src/test/java/it/cavallium/strangedb/utils/NTestUtils.java
+++ b/src/test/java/it/cavallium/strangedb/utils/NTestUtils.java
@@ -247,32 +247,38 @@ public class NTestUtils {
super(databaseTools);
}
- @DbPropertyGetter(id = 0, type = DbDataType.OBJECT)
+ @DbProperty(id = 0, type = DbDataType.OBJECT)
+ @DbPropertyGetter
public String get7() {
return getProperty();
}
- @DbPropertyGetter(id = 1, type = DbDataType.REFERENCES_LIST)
+ @DbProperty(id = 1, type = DbDataType.REFERENCES_LIST)
+ @DbPropertyGetter
public LongArrayList get8() {
return getProperty();
}
- @DbPropertyGetter(id = 2, type = DbDataType.ENHANCED_OBJECT)
+ @DbProperty(id = 2, type = DbDataType.ENHANCED_OBJECT)
+ @DbPropertyGetter
public NSimplestClass get9() {
return getProperty();
}
- @DbPropertySetter(id = 0, type = DbDataType.OBJECT)
+ @DbProperty(id = 0, type = DbDataType.OBJECT)
+ @DbPropertySetter
public void set7(String val) {
setProperty(val);
}
- @DbPropertySetter(id = 1, type = DbDataType.REFERENCES_LIST)
+ @DbProperty(id = 1, type = DbDataType.REFERENCES_LIST)
+ @DbPropertySetter
public void set8(LongArrayList val) {
setProperty(val);
}
- @DbPropertySetter(id = 2, type = DbDataType.ENHANCED_OBJECT)
+ @DbProperty(id = 2, type = DbDataType.ENHANCED_OBJECT)
+ @DbPropertySetter
public void set9(NSimplestClass val) {
setProperty(val);
}