ClassDescriptor.java :  » Database-DBMS » perst » org » garret » perst » impl » Java Open Source

Java Open Source » Database DBMS » perst 
perst » org » garret » perst » impl » ClassDescriptor.java
package org.garret.perst.impl;
import  org.garret.perst.*;
import  java.lang.reflect.*;
import  java.util.*;

public final class ClassDescriptor extends Persistent { 
    ClassDescriptor   next;
    String            name;
    boolean           hasReferences;
    FieldDescriptor[] allFields;
    CustomAllocator   allocator;

    static class FieldDescriptor extends Persistent implements Comparable { 
        String          fieldName;
        String          className;
        int             type;
        ClassDescriptor valueDesc;
        transient Field field;

        public int compareTo(Object o) { 
            return fieldName.compareTo(((FieldDescriptor)o).fieldName);
        }

        public boolean equals(FieldDescriptor fd) { 
            return fieldName.equals(fd.fieldName) 
                && className.equals(fd.className)
                && valueDesc == fd.valueDesc
                && type == fd.type;
        }
    }    

    transient Class       cls;
    transient Constructor loadConstructor;
    transient LoadFactory factory;
    transient Object[]    constructorParams;
    transient boolean     hasSubclasses;
    transient boolean     resolved;
    
    static ReflectionProvider reflectionProvider; 

    static boolean            reverseMembersOrder;

    public static final int tpBoolean          = 0;
    public static final int tpByte             = 1;
    public static final int tpChar             = 2;
    public static final int tpShort            = 3;
    public static final int tpInt              = 4;
    public static final int tpLong             = 5;
    public static final int tpFloat            = 6;
    public static final int tpDouble           = 7;
    public static final int tpString           = 8;
    public static final int tpDate             = 9;
    public static final int tpObject           = 10;
    public static final int tpValue            = 11;
    public static final int tpRaw              = 12;
    public static final int tpLink             = 13;
    public static final int tpEnum             = 14;
    public static final int tpCustom           = 15;
    public static final int tpArrayOfBoolean   = 20;
    public static final int tpArrayOfByte      = 21;
    public static final int tpArrayOfChar      = 22;
    public static final int tpArrayOfShort     = 23;
    public static final int tpArrayOfInt       = 24;
    public static final int tpArrayOfLong      = 25;
    public static final int tpArrayOfFloat     = 26;
    public static final int tpArrayOfDouble    = 27;
    public static final int tpArrayOfString    = 28;
    public static final int tpArrayOfDate      = 29;
    public static final int tpArrayOfObject    = 30;
    public static final int tpArrayOfValue     = 31;
    public static final int tpArrayOfRaw       = 32;
    public static final int tpArrayOfLink      = 33; // not supported
    public static final int tpArrayOfEnum      = 34;

    static final String signature[] = {
        "boolean", 
        "byte",
        "char",
        "short",
        "int",
        "long",
        "float",
        "double",
        "String",
        "Date",
        "Object",
        "Value",
        "Raw",
        "Link",
        "enum",
        "", 
        "", 
        "", 
        "", 
        "", 
        "", 
        "ArrayOfBoolean",
        "ArrayOfByte",
        "ArrayOfChar",
        "ArrayOfShort",
        "ArrayOfInt",
        "ArrayOfLong",
        "ArrayOfFloat",
        "ArrayOfDouble",
        "ArrayOfEnum",
        "ArrayOfString",
        "ArrayOfDate",
        "ArrayOfObject",
        "ArrayOfValue",
        "ArrayOfRaw",
        "ArrayOfLink",
        "ArrayOfEnum"
    };
        

    static final int sizeof[] = {
        1, // tpBoolean
        1, // tpByte
        2, // tpChar
        2, // tpShort
        4, // tpInt
        8, // tpLong
        4, // tpFloat
        8, // tpDouble
        0, // tpString
        8, // tpDate
        4, // tpObject
        0, // tpValue
        0, // tpRaw
        0, // tpLink
        4  // tpEnum
     };

    static final Class[] perstConstructorProfile = new Class[]{ClassDescriptor.class};

    static ReflectionProvider getReflectionProvider() { 
        if (reflectionProvider == null) { 
            try {
                Class.forName("sun.misc.Unsafe");
                String cls = "org.garret.perst.impl.sun14.Sun14ReflectionProvider";
                reflectionProvider = (ReflectionProvider)Class.forName(cls).newInstance();
            } catch (Throwable x) { 
                reflectionProvider = new StandardReflectionProvider();
            }
        }
        return reflectionProvider;
    } 
           

    public boolean equals(ClassDescriptor cd) { 
        if (cd == null || allFields.length != cd.allFields.length) { 
            return false;
        }
        for (int i = 0; i < allFields.length; i++) { 
            if (!allFields[i].equals(cd.allFields[i])) { 
                return false;
            }
        }
        return true;
    }
        

    Object newInstance() {
        if (factory != null) { 
            return factory.create(this);
        } else { 
            try { 
                return loadConstructor.newInstance(constructorParams);
            } catch (Exception x) { 
                throw new StorageError(StorageError.CONSTRUCTOR_FAILURE, cls, x);
            }
        }
    }

    void buildFieldList(StorageImpl storage, Class cls, ArrayList list) { 
        Class superclass = cls.getSuperclass();
        if (superclass != null) { 
            buildFieldList(storage, superclass, list);
        }
        Field[] flds = cls.getDeclaredFields();
        if (storage.getDatabaseFormatVersion() >= 2) { 
            Arrays.sort(flds, new Comparator<Field>() { public int compare(Field f1, Field f2) { return f1.getName().compareTo(f2.getName()); } });
        } else { // preserve backward compatibility
            if (ClassDescriptor.class.equals(cls)) { 
                for (int i = 0; i < flds.length; i++) { 
                    if ((flds[i].getModifiers() & (Modifier.TRANSIENT|Modifier.STATIC)) == 0) {
                        if (!"next".equals(flds[i].getName())) { 
                            reverseMembersOrder = true;
                        }
                        break;
                    }
                }
            }
            if (reverseMembersOrder) { 
                for (int i = 0, n = flds.length; i < (n >> 1); i++) { 
                    Field f = flds[i];
                    flds[i] = flds[n-i-1];
                    flds[n-i-1] = f;
                }
            }
        }
        for (int i = 0; i < flds.length; i++) { 
            Field f = flds[i];
            if (!f.isSynthetic() && (f.getModifiers() & (Modifier.TRANSIENT|Modifier.STATIC)) == 0) {
                try { 
                    f.setAccessible(true);
                } catch (Exception x) {}
                FieldDescriptor fd = new FieldDescriptor();
                fd.field = f;
                fd.fieldName = f.getName();
                fd.className = cls.getName();
                int type = getTypeCode(f.getType());
                switch (type) {
                  case tpObject:
                  case tpLink:
                  case tpArrayOfObject:
                    hasReferences = true;
                    break;
                  case tpValue:
                    fd.valueDesc = storage.getClassDescriptor(f.getType());
                    hasReferences |= fd.valueDesc.hasReferences;                    
                    break;
                  case tpArrayOfValue:
                    fd.valueDesc = storage.getClassDescriptor(f.getType().getComponentType());
                    hasReferences |= fd.valueDesc.hasReferences;
                }
                fd.type = type;
                list.add(fd);
            }
        }
    }

    public static int getTypeCode(Class c) { 
        int type;
        if (c.equals(byte.class)) { 
            type = tpByte;
        } else if (c.equals(short.class)) {
            type = tpShort;
        } else if (c.equals(char.class)) {
            type = tpChar;
        } else if (c.equals(int.class)) {
            type = tpInt;
        } else if (c.equals(long.class)) {
            type = tpLong;
        } else if (c.equals(float.class)) {
            type = tpFloat;
        } else if (c.equals(double.class)) {
            type = tpDouble;
        } else if (c.equals(String.class)) {
            type = tpString;
        } else if (c.equals(boolean.class)) {
            type = tpBoolean;
        } else if (c.isEnum()) {
            type = tpEnum;
        } else if (c.equals(java.util.Date.class)) {
            type = tpDate;
        } else if (IPersistent.class.isAssignableFrom(c)) {
            type = tpObject;
        } else if (IValue.class.isAssignableFrom(c)) {
            type = tpValue;
        } else if (c.equals(Link.class)) {
            type = tpLink;
        } else if (c.isArray()) { 
            type = getTypeCode(c.getComponentType());
            if (type >= tpLink) { 
                throw new StorageError(StorageError.UNSUPPORTED_TYPE, c);
            }
            type += tpArrayOfBoolean;
        } else if (CustomSerializable.class.isAssignableFrom(c)) {
            type = tpCustom;            
        } else if (c.equals(Object.class) || Comparable.class.isAssignableFrom(c)) {
            type = tpRaw;
        } else if (serializeNonPersistentObjects) {
            type = tpRaw;            
        } else if (treateAnyNonPersistentObjectAsValue) {
            if (c.equals(Object.class)) { 
                throw new StorageError(StorageError.EMPTY_VALUE);
            }
            type = tpValue;            
        } else { 
            throw new StorageError(StorageError.UNSUPPORTED_TYPE, c);
        }
        return type;
    }

    static boolean treateAnyNonPersistentObjectAsValue = Boolean.getBoolean("perst.implicit.values");
    static boolean serializeNonPersistentObjects = Boolean.getBoolean("perst.serialize.transient.objects");

    ClassDescriptor() {}


    private void locateConstructor() { 
        try { 
            //Class c = Class.forName(cls.getName() + "LoadFactory");
            Class c = Thread.currentThread().getContextClassLoader().loadClass(cls.getName() + "LoadFactory");
            factory = (LoadFactory)c.newInstance();
        } catch (Exception x1) { 
            try {             
                loadConstructor = cls.getDeclaredConstructor(perstConstructorProfile);
                constructorParams = new Object[]{this};
            } catch (NoSuchMethodException x2) {
                try { 
                    loadConstructor = getReflectionProvider().getDefaultConstructor(cls);
                    constructorParams = null;
                } catch (Exception x3) {
                    throw new StorageError(StorageError.DESCRIPTOR_FAILURE, cls, x3);
                }
            }
            try { 
                loadConstructor.setAccessible(true);
            } catch (Exception x) {}
        }
    }

    ClassDescriptor(StorageImpl storage, Class cls) { 
        this.cls = cls;
        name = getClassName(cls);
        ArrayList list = new ArrayList();
        buildFieldList(storage, cls, list);
        allFields = (FieldDescriptor[])list.toArray(new FieldDescriptor[list.size()]);
        locateConstructor();
        resolved = true;
    }

    protected static Field locateField(Class scope, String name) { 
        try { 
            do { 
                try { 
                    Field fld = scope.getDeclaredField(name);                
                    try { 
                        fld.setAccessible(true);
                    } catch (Exception e) {}
                    return fld;
                } catch (NoSuchFieldException x) { 
                    scope = scope.getSuperclass();
                }
            } while (scope != null);
        } catch (Exception x) {
            throw new StorageError(StorageError.ACCESS_VIOLATION, scope.getName() + "." + name, x);
        }
        return null;
    }
        
    public static String getClassName(Class cls) { 
        ClassLoader loader = cls.getClassLoader();
        return (loader instanceof INamedClassLoader) 
            ? ((INamedClassLoader)loader).getName() + ':' + cls.getName()
            : cls.getName();
    }
        
    public static Class loadClass(Storage storage, String name) { 
        if (storage != null) { 
            int col = name.indexOf(':');
            ClassLoader loader;
            if (col >= 0) { 
                loader = storage.findClassLoader(name.substring(0, col));
                if (loader == null) { 
                    // just ignore  this class
                    return null; 
                }
                name = name.substring(col+1);
            } else { 
                loader = storage.getClassLoader();
            }
            if (loader != null) { 
                try { 
                    return loader.loadClass(name);
                } catch (ClassNotFoundException x) {}
            }
        }
        try { 
            return Thread.currentThread().getContextClassLoader().loadClass(name);
            // return Class.forName(name);
        } catch (ClassNotFoundException x) { 
            throw new StorageError(StorageError.CLASS_NOT_FOUND, name, x);
        }
    }

    public void onLoad() {         
        cls = loadClass(getStorage(), name);
        Class scope = cls;
        int n = allFields.length;
        for (int i = n; --i >= 0;) { 
            FieldDescriptor fd = allFields[i];
            fd.load();
            if (!fd.className.equals(scope.getName())) {
                for (scope = cls; scope != null; scope = scope.getSuperclass()) { 
                    if (fd.className.equals(scope.getName())) {
                        break;
                    }
                }
            }
            if (scope != null) {
                try { 
                    Field f = scope.getDeclaredField(fd.fieldName);
                    if ((f.getModifiers() & (Modifier.TRANSIENT|Modifier.STATIC)) == 0) {
                        try { 
                            f.setAccessible(true);
                        } catch (Exception e) {}
                        fd.field = f;
                    }
                } catch (NoSuchFieldException x) {}
            } else { 
                scope = cls;
            }
        }
        for (int i = n; --i >= 0;) { 
            FieldDescriptor fd = allFields[i];
            if (fd.field == null) { 
            hierarchyLoop:
                for (scope = cls; scope != null; scope = scope.getSuperclass()) { 
                    try { 
                        Field f = scope.getDeclaredField(fd.fieldName);
                        if ((f.getModifiers() & (Modifier.TRANSIENT|Modifier.STATIC)) == 0) {
                            for (int j = 0; j < n; j++) { 
                                if (allFields[j].field == f) { 
                                    continue hierarchyLoop;
                                }
                            }
                            try { 
                                f.setAccessible(true);
                            } catch (Exception e) {}
                            fd.field = f;
                            break;
                        }
                    } catch (NoSuchFieldException x) {}
                }
            }
        }
        locateConstructor();
        StorageImpl s = (StorageImpl)getStorage();
        if (s.classDescMap.get(cls) == null) { 
            s.classDescMap.put(cls, this);
        }
    }

       
    void resolve() {
        if (!resolved) { 
            StorageImpl classStorage = (StorageImpl)getStorage();
            ClassDescriptor desc = new ClassDescriptor(classStorage, cls);
            resolved = true;
            if (!desc.equals(this)) { 
                classStorage.registerClassDescriptor(desc);
            }
        }
    }            

    public boolean recursiveLoading() { 
        return false;
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.