package org.warp.cowdb; import org.apache.commons.lang3.reflect.MethodUtils; import org.warp.jcwdb.ann.DBDataType; import org.warp.jcwdb.ann.DBPropertyGetter; import org.warp.jcwdb.ann.DBPropertySetter; import java.io.IOError; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Map; public abstract class EnhancedObject { protected IDatabase database; private Field[] fields; private DBDataType[] fieldTypes; private long[] fieldReferences; private Method[] propertyGetters; private Method[] propertySetters; private DBDataType[] propertyTypes; private long[] propertyReferences; private boolean[] loadedProperties; private Object[] loadedPropertyValues; private Map setterMethods; private Map getterMethods; public EnhancedObject() { } public EnhancedObject(IDatabase database) throws IOException { this.database = database; database.getDataInitializer().initializeDBObject(this); } public abstract void initialize() throws IOException; public void setFields(Field[] fields, DBDataType[] fieldTypes, long[] fieldReferences) { this.fields = fields; this.fieldTypes = fieldTypes; this.fieldReferences = fieldReferences; } 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 setterMethods, Map 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(fieldReferences, fieldTypes, fields, propertyReferences, propertyTypes, loadedPropertyValues); } public 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); } } @SuppressWarnings("unchecked") private T getProperty(int propertyId) throws IOException { if (!loadedProperties[propertyId]) { long propertyUID = propertyReferences[propertyId]; database.getObjectsIO().loadProperty(this, propertyId, propertyGetters[propertyId], propertyTypes[propertyId], propertyUID); } return (T) loadedPropertyValues[propertyId]; } 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()); setProperty(propertyAnnotation.id(), value); } public void setProperty(int propertyId, T value) { loadedPropertyValues[propertyId] = value; loadedProperties[propertyId] = true; } }