138 lines
4.6 KiB
Java
138 lines
4.6 KiB
Java
package org.warp.jcwdb.ann;
|
|
|
|
import org.apache.commons.lang3.reflect.MethodUtils;
|
|
|
|
import java.io.IOError;
|
|
import java.io.IOException;
|
|
import java.lang.reflect.Field;
|
|
import java.lang.reflect.Method;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.Map;
|
|
|
|
public abstract class DBObject {
|
|
protected JCWDatabase database;
|
|
private Field[] fields;
|
|
private DBDataType[] fieldTypes;
|
|
private long[] fieldUIDs;
|
|
|
|
private Method[] propertyGetters;
|
|
private Method[] propertySetters;
|
|
private DBDataType[] propertyTypes;
|
|
private long[] propertyUIDs;
|
|
private boolean[] loadedProperties;
|
|
private Object[] loadedPropertyValues;
|
|
private Map<String, DBPropertySetter> setterMethods;
|
|
private Map<String, DBPropertyGetter> getterMethods;
|
|
private final Object fieldsAccessLock = new Object();
|
|
private final Object propertiesAccessLock = new Object();
|
|
|
|
public DBObject() {
|
|
|
|
}
|
|
|
|
public DBObject(JCWDatabase database) throws IOException {
|
|
this.database = database;
|
|
database.initializeDBObject(this);
|
|
}
|
|
|
|
public abstract void initialize() throws IOException;
|
|
|
|
|
|
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(DBPropertyGetter.class).id();
|
|
return getProperty(propertyId);
|
|
} catch (IOException | NoSuchMethodException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
<T> void setLoadedProperty(int propertyId, T value) {
|
|
loadedPropertyValues[propertyId] = value;
|
|
loadedProperties[propertyId] = true;
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
private <T> T getProperty(int propertyId) throws IOException {
|
|
synchronized (propertiesAccessLock) {
|
|
if (!loadedProperties[propertyId]) {
|
|
long propertyUID = propertyUIDs[propertyId];
|
|
database.getDataLoader().loadProperty(this, propertyId, propertyGetters[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));
|
|
DBPropertySetter propertyAnnotation = setterMethods.get(stackFrame.getMethodName());
|
|
setProperty(propertyAnnotation.id(), propertyAnnotation.type(), value);
|
|
}
|
|
|
|
public <T> void setProperty(int propertyId, DBDataType propertyType, T value) {
|
|
synchronized (propertiesAccessLock) {
|
|
loadedPropertyValues[propertyId] = value;
|
|
loadedProperties[propertyId] = true;
|
|
}
|
|
}
|
|
|
|
public void writeToDisk(long uid) {
|
|
//System.err.println("Saving object " + uid + ":" + this);
|
|
try {
|
|
synchronized (propertiesAccessLock) {
|
|
synchronized (fieldsAccessLock) {
|
|
database.getDataLoader().writeObjectInfo(uid, fieldUIDs, propertyUIDs);
|
|
}
|
|
}
|
|
synchronized (fieldsAccessLock) {
|
|
for (int i = 0; i < fieldUIDs.length; i++) {
|
|
try {
|
|
database.getDataLoader().writeObjectProperty(fieldUIDs[i], fieldTypes[i], fields[i].get(this));
|
|
} catch (IllegalAccessException e) {
|
|
throw new IOError(e);
|
|
}
|
|
}
|
|
}
|
|
synchronized (propertiesAccessLock) {
|
|
for (int i = 0; i < propertyUIDs.length; i++) {
|
|
database.getDataLoader().writeObjectProperty(propertyUIDs[i], propertyTypes[i], loadedPropertyValues[i]);
|
|
}
|
|
}
|
|
} catch (IOException e) {
|
|
throw new IOError(e);
|
|
}
|
|
}
|
|
|
|
public final void setFields(Field[] fields, DBDataType[] fieldTypes, long[] fieldUIDs) {
|
|
synchronized (fieldsAccessLock) {
|
|
this.fields = fields;
|
|
this.fieldTypes = fieldTypes;
|
|
this.fieldUIDs = fieldUIDs;
|
|
}
|
|
}
|
|
|
|
public final void setProperties(Method[] propertyGetters, Method[] propertySetters, DBDataType[] propertyTypes, long[] propertyUIDs, Map<String, DBPropertySetter> setterMethods, Map<String, DBPropertyGetter> getterMethods) {
|
|
synchronized (propertiesAccessLock) {
|
|
this.propertyGetters = propertyGetters;
|
|
this.propertySetters = propertySetters;
|
|
this.propertyTypes = propertyTypes;
|
|
this.propertyUIDs = propertyUIDs;
|
|
this.loadedProperties = new boolean[this.propertyUIDs.length];
|
|
this.loadedPropertyValues = new Object[this.propertyUIDs.length];
|
|
this.setterMethods = setterMethods;
|
|
this.getterMethods = getterMethods;
|
|
}
|
|
}
|
|
|
|
Method[] getPropertyGetters() {
|
|
return MethodUtils.getMethodsWithAnnotation(this.getClass(), DBPropertyGetter.class);
|
|
}
|
|
|
|
public Method[] getPropertySetters() {
|
|
return MethodUtils.getMethodsWithAnnotation(this.getClass(), DBPropertySetter.class);
|
|
}
|
|
}
|