strangedb/src/main/java/it/cavallium/strangedb/java/objects/EnhancedObject.java

136 lines
5.1 KiB
Java

package it.cavallium.strangedb.java.objects;
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;
public abstract class EnhancedObject {
protected final int version;
protected IDatabaseTools databaseTools;
private Field[] fields;
private DbDataType[] fieldTypes;
private long[] fieldReferences;
private Field[] primitiveFields;
private DbPrimitiveType[] primitiveFieldTypes;
private long primitiveFieldsDataReference;
private Method[] propertyGetters;
private Method[] propertySetters;
private DbDataType[] propertyTypes;
private long[] propertyReferences;
private boolean[] loadedProperties;
private Object[] loadedPropertyValues;
private Map<String, DbProperty> setterMethods;
private Map<String, DbProperty> getterMethods;
public EnhancedObject() {
version = getClassVersion();
}
public EnhancedObject(IDatabaseTools databaseTools) throws IOException {
this.databaseTools = databaseTools;
version = getClassVersion();
databaseTools.initializeEnhancedObject(this);
}
public void setFields(Field[] fields, DbDataType[] fieldTypes, long[] fieldReferences) {
this.fields = fields;
this.fieldTypes = fieldTypes;
this.fieldReferences = fieldReferences;
}
public void setPrimitiveFields(Field[] fields, DbPrimitiveType[] fieldTypes, long primitiveFieldsDataReference) {
this.primitiveFields = fields;
this.primitiveFieldTypes = fieldTypes;
this.primitiveFieldsDataReference = primitiveFieldsDataReference;
}
public Method[] getPropertyGetters() {
return MethodUtils.getMethodsWithAnnotation(this.getClass(), DbPropertyGetter.class);
}
public Method[] getPropertySetters() {
return MethodUtils.getMethodsWithAnnotation(this.getClass(), DbPropertySetter.class);
}
public void setProperties(Method[] propertyGetters, Method[] propertySetters, DbDataType[] propertyTypes, long[] propertyReferences, Map<String, DbPropertySetter> setterMethods, Map<String, DbPropertyGetter> getterMethods) {
this.propertyGetters = propertyGetters;
this.propertySetters = propertySetters;
this.propertyTypes = propertyTypes;
this.propertyReferences = propertyReferences;
this.loadedProperties = new boolean[this.propertyReferences.length];
this.loadedPropertyValues = new Object[this.propertyReferences.length];
this.setterMethods = setterMethods;
this.getterMethods = getterMethods;
}
public EnhancedObjectFullInfo getAllInfo() {
return new EnhancedObjectFullInfo(version, fieldReferences, fieldTypes, fields, primitiveFieldsDataReference, primitiveFieldTypes, primitiveFields, propertyReferences, propertyTypes, loadedPropertyValues);
}
public <T> T getProperty() {
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(DbProperty.class).id();
return getProperty(propertyId);
} catch (IOException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
public <T> T getProperty(int propertyId) throws IOException {
if (!loadedProperties[propertyId]) {
long propertyUID = propertyReferences[propertyId];
databaseTools.getObjectsIO().loadProperty(this, propertyId, propertyTypes[propertyId], propertyUID);
}
return (T) loadedPropertyValues[propertyId];
}
public <T> 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));
DbProperty propertyAnnotation = setterMethods.get(stackFrame.getMethodName());
setProperty(propertyAnnotation.id(), value);
}
public <T> void setProperty(int propertyId, T value) {
loadedPropertyValues[propertyId] = value;
loadedProperties[propertyId] = true;
}
private int getClassVersion() {
DbClass classAnnotation = this.getClass().getAnnotation(DbClass.class);
return classAnnotation == null ? 0 : classAnnotation.version();
}
/**
* Called when an unloaded class is older than the actual version
* @param oldObjectVersion
* @param enhancedObjectUpgrader
* @throws IOException
*/
public void onUpgrade(int oldObjectVersion, EnhancedObjectUpgrader enhancedObjectUpgrader) throws IOException {
throw new NotImplementedException("Method onUpgrade() is not implemented for class " + this.getClass().getSimpleName());
}
public IDatabaseTools getDatabaseTools() {
return databaseTools;
}
public void setDatabaseTools(IDatabaseTools databaseTools) {
this.databaseTools = databaseTools;
}
}