/* This file is part of the db4o object database http://www.db4o.com Copyright (C) 2004 - 2011 Versant Corporation http://www.versant.com db4o is free software; you can redistribute it and/or modify it under the terms of version 3 of the GNU General Public License as published by the Free Software Foundation. db4o is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. */ package com.db4o.cs.internal; import java.util.*; import com.db4o.foundation.*; import com.db4o.internal.*; import com.db4o.reflect.*; import com.db4o.reflect.generic.*; public class ClassInfoHelper { private Hashtable4 _classMetaTable = new Hashtable4(); private Hashtable4 _genericClassTable = new Hashtable4(); private Config4Impl _config; public ClassInfoHelper(Config4Impl config) { _config = config; } public ClassInfo getClassMeta(ReflectClass claxx) { if (isObjectClass(claxx)) { return ClassInfo.newSystemClass(claxx.getName()); } ClassInfo existing = lookupClassMeta(claxx.getName()); if (existing != null) { return existing; } return newUserClassMeta(claxx); } private ClassInfo newUserClassMeta(ReflectClass claxx) { ClassInfo classMeta = ClassInfo.newUserClass(claxx.getName()); classMeta.setSuperClass(mapSuperclass(claxx)); registerClassMeta(claxx.getName(), classMeta); classMeta.setFields( mapFields(claxx.getDeclaredFields(), shouldStoreTransientFields(claxx))); return classMeta; } private boolean shouldStoreTransientFields(ReflectClass claxx) { Config4Class configClass = _config.configClass(claxx.getName()); return configClass == null ? false : configClass.storeTransientFields(); } private ClassInfo mapSuperclass(ReflectClass claxx) { ReflectClass superClass = claxx.getSuperclass(); if (superClass != null) { return getClassMeta(superClass); } return null; } private FieldInfo[] mapFields(ReflectField[] fields, boolean shouldStoreTransientFields) { if (!shouldStoreTransientFields) { fields = filterTransientFields(fields); } FieldInfo[] fieldsMeta = new FieldInfo[fields.length]; for (int i = 0; i < fields.length; ++i) { final ReflectField field = fields[i]; boolean isArray = field.getFieldType().isArray(); ReflectClass fieldClass = isArray ? field.getFieldType().getComponentType() : field.getFieldType(); boolean isPrimitive = fieldClass.isPrimitive(); // TODO: need to handle NArray, currently it ignores NArray and alway sets NArray flag false. fieldsMeta[i] = new FieldInfo(field.getName(), getClassMeta(fieldClass), isPrimitive, isArray, false); } return fieldsMeta; } private ReflectField[] filterTransientFields(ReflectField[] fields) { List<ReflectField> filteredFields = new ArrayList<ReflectField>(); for(ReflectField field : fields) { if (!field.isTransient()) { filteredFields.add(field); } } return filteredFields.toArray(new ReflectField[filteredFields.size()]); } private static boolean isObjectClass(ReflectClass claxx) { // TODO: We should send the whole class meta if we'd like to support // java and .net communication (We have this request in our user forum // http://developer.db4o.com/forums/thread/31504.aspx). If we only want // to support java & .net platform separately, then this method should // be moved to Platform4. //return className.startsWith("java.lang.Object") || className.startsWith("System.Object"); return claxx.reflector().forClass(Const4.CLASS_OBJECT) == claxx; } private ClassInfo lookupClassMeta(String className) { return (ClassInfo) _classMetaTable.get(className); } private void registerClassMeta(String className, ClassInfo classMeta) { _classMetaTable.put(className, classMeta); } public GenericClass classMetaToGenericClass(GenericReflector reflector, ClassInfo classMeta) { if (classMeta.isSystemClass()) { return (GenericClass) reflector.forName(classMeta.getClassName()); } String className = classMeta.getClassName(); // look up from generic class table. GenericClass genericClass = lookupGenericClass(className); if (genericClass != null) { return genericClass; } ReflectClass reflectClass = reflector.forName(className); if(reflectClass != null) { return (GenericClass) reflectClass; } GenericClass genericSuperClass = null; ClassInfo superClassMeta = classMeta.getSuperClass(); if (superClassMeta != null) { genericSuperClass = classMetaToGenericClass(reflector, superClassMeta); } genericClass = new GenericClass(reflector, null, className, genericSuperClass); registerGenericClass(className, genericClass); FieldInfo[] fields = classMeta.getFields(); GenericField[] genericFields = new GenericField[fields.length]; for (int i = 0; i < fields.length; ++i) { ClassInfo fieldClassMeta = fields[i].getFieldClass(); String fieldName = fields[i].getFieldName(); GenericClass genericFieldClass = classMetaToGenericClass(reflector, fieldClassMeta); genericFields[i] = new GenericField(fieldName, genericFieldClass, fields[i]._isPrimitive); } genericClass.initFields(genericFields); return genericClass; } private GenericClass lookupGenericClass(String className) { return (GenericClass) _genericClassTable.get(className); } private void registerGenericClass(String className, GenericClass classMeta) { _genericClassTable.put(className, classMeta); ((GenericReflector)classMeta.reflector()).register(classMeta); } }