001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package com.db4o.j2me.bloat;
022:
023: import java.lang.reflect.*;
024: import java.util.*;
025:
026: import EDU.purdue.cs.bloat.editor.*;
027: import EDU.purdue.cs.bloat.editor.Type;
028: import EDU.purdue.cs.bloat.file.*;
029: import EDU.purdue.cs.bloat.reflect.*;
030: import EDU.purdue.cs.bloat.reflect.FieldInfo;
031:
032: import com.db4o.reflect.self.*;
033: import com.db4o.reflect.self.ClassInfo;
034:
035: public class RegistryEnhancer {
036: private static final String COMPONENTTYPE_METHODNAME = "componentType";
037:
038: private static final String ARRAYFOR_METHODNAME = "arrayFor";
039:
040: private static final String INFOFOR_METHODNAME = "infoFor";
041:
042: private static final String CLASSINFO_CONSTNAME = "CLASSINFO";
043:
044: private ClassEditor _ce;
045:
046: private Class[] _clazzes;
047:
048: private BloatJ2MEContext _context;
049:
050: public RegistryEnhancer(BloatJ2MEContext context, ClassEditor ce,
051: Class clazz) {
052: this ._ce = ce;
053: this ._clazzes = createClasses(clazz);
054: this ._context = context;
055: }
056:
057: private static Class[] createClasses(Class concrete) {
058: List list = new ArrayList();
059: Class cur = concrete;
060: while (cur != Object.class) {
061: list.add(cur);
062: cur = cur.getSuperclass();
063: }
064: return (Class[]) list.toArray(new Class[list.size()]);
065: }
066:
067: public void generate() {
068: _context.addNoArgConstructor(_ce);
069: generateCLASSINFOField();
070: generateInfoForMethod();
071: generateArrayForMethod();
072: generateComponentTypeMethod();
073: }
074:
075: private void generateCLASSINFOField() {
076: FieldEditor fe = _context.createField(_ce, 26, Type
077: .getType(Hashtable.class), CLASSINFO_CONSTNAME);
078:
079: MethodBuilder builder = new MethodBuilder(_context, _ce,
080: Modifiers.STATIC, void.class, "<clinit>", new Class[0],
081: new Class[0]);
082: builder.newRef(Hashtable.class);
083: builder.dup();
084: builder.invokeSpecial(_context.getType(Hashtable.class),
085: BloatJ2MEContext.INIT_METHODNAME, new Type[0],
086: Type.VOID);
087: builder.putstatic(_ce.type(), Hashtable.class,
088: CLASSINFO_CONSTNAME);
089: for (int classIdx = 0; classIdx < _clazzes.length; classIdx++) {
090: builder.getstatic(_ce.type(), Hashtable.class,
091: CLASSINFO_CONSTNAME);
092: generateInfoForClass(builder, _clazzes[classIdx]);
093: }
094:
095: builder.returnInstruction();
096: builder.commit();
097: fe.commit();
098:
099: }
100:
101: private void generateInfoForClass(MethodBuilder builder, Class clazz) {
102: builder.invokeLoadClassConstMethod(clazz);
103: builder.newRef(com.db4o.reflect.self.ClassInfo.class);
104: builder.dup();
105: FieldInfo[] fieldsInf = collectFieldsOfClass(clazz);
106: builder.ldc(isAbstractClass(clazz));
107: builder.invokeLoadClassConstMethod(clazz.getSuperclass());
108: builder.ldc(fieldsInf.length);
109: builder.anewarray(com.db4o.reflect.self.FieldInfo.class);
110: for (int i = 0; i < fieldsInf.length; i++) {
111: generateInfoForField(builder, _context.fieldEditor(clazz,
112: fieldsInf[i]), i);
113: }
114: builder
115: .invokeSpecial(
116: _context.getType(ClassInfo.class),
117: BloatJ2MEContext.INIT_METHODNAME,
118: new Type[] {
119: Type.BOOLEAN,
120: Type.CLASS,
121: _context
122: .getType(com.db4o.reflect.self.FieldInfo[].class) },
123: Type.VOID);
124: builder.invokeVirtual(_context.getType(Hashtable.class), "put",
125: new Type[] { Type.OBJECT, Type.OBJECT }, Type.OBJECT);
126: }
127:
128: private void generateInfoForField(MethodBuilder builder,
129: FieldEditor fieldEditor, int arrIdx) {
130: builder.dup();
131: builder.ldc(arrIdx);
132: builder.newRef(com.db4o.reflect.self.FieldInfo.class);
133: builder.dup();
134: builder.ldc(fieldEditor.name());
135: Class wrapper = PrimitiveUtil.wrapper(fieldEditor.type());
136: if (wrapper != null) {
137: builder.getstatic(wrapper, Class.class, "TYPE");
138: } else {
139: builder.invokeLoadClassConstMethod(fieldEditor.type()
140: .className());
141: }
142: builder.ldc(fieldEditor.isPublic());
143: builder.ldc(fieldEditor.isStatic());
144: builder.ldc(fieldEditor.isTransient());
145: builder.invokeSpecial(_context
146: .getType(com.db4o.reflect.self.FieldInfo.class),
147: BloatJ2MEContext.INIT_METHODNAME, new Type[] {
148: Type.STRING, Type.CLASS, Type.BOOLEAN,
149: Type.BOOLEAN, Type.BOOLEAN }, Type.VOID);
150: builder.aastore();
151: }
152:
153: private FieldInfo[] collectFieldsOfClass(Class clazz) {
154: ClassEditor ce = null;
155: FieldInfo[] fields = null;
156: try {
157: ce = new ClassEditor(null, new ClassFileLoader()
158: .loadClass(clazz.getName()));
159: fields = ce.fields();
160: } catch (ClassNotFoundException e) {
161: e.printStackTrace();
162: }
163: return fields;
164: }
165:
166: private boolean isAbstractClass(Class clazz) {
167: return Modifier.isAbstract(clazz.getModifiers());
168: }
169:
170: private void generateInfoForMethod() {
171: MethodBuilder builder = new MethodBuilder(_context, _ce,
172: Modifiers.PUBLIC,
173: com.db4o.reflect.self.ClassInfo.class,
174: INFOFOR_METHODNAME, new Class[] { Class.class }, null);
175: builder.getstatic(_ce.type(), Hashtable.class,
176: CLASSINFO_CONSTNAME);
177: builder.aload(1);
178: builder.invokeVirtual(_context.getType(Hashtable.class), "get",
179: new Type[] { Type.OBJECT }, Type.OBJECT);
180: builder.checkcast(ClassInfo.class);
181: builder.areturn();
182: builder.commit();
183:
184: }
185:
186: private void generateArrayForMethod() {
187: MethodBuilder builder = new MethodBuilder(_context, _ce,
188: Modifiers.PUBLIC, Object.class, ARRAYFOR_METHODNAME,
189: new Class[] { Class.class, Integer.TYPE }, null);
190: int labelIdx = 1;
191: for (int classIdx = 0; classIdx < _clazzes.length; classIdx++) {
192: builder.invokeLoadClassConstMethod(_clazzes[classIdx]);
193: builder.aload(1);
194: builder.invokeVirtual(Type.CLASS, "isAssignableFrom",
195: new Type[] { Type.CLASS }, Type.BOOLEAN);
196: builder.ifeq(labelIdx);
197: builder.iload(2);
198: builder.newarray(_clazzes[classIdx]);
199: builder.areturn();
200: builder.label(labelIdx);
201: labelIdx++;
202: }
203: builder.aload(0);
204: builder.aload(1);
205: builder.iload(2);
206: builder.invokeSpecial(_context
207: .getType(SelfReflectionRegistry.class),
208: ARRAYFOR_METHODNAME, new Type[] { Type.CLASS,
209: Type.INTEGER }, Type.OBJECT);
210: builder.areturn();
211: builder.commit();
212: }
213:
214: private void generateComponentTypeMethod() {
215: MethodBuilder builder = new MethodBuilder(_context, _ce,
216: Modifiers.PUBLIC, Class.class,
217: COMPONENTTYPE_METHODNAME, new Class[] { Class.class },
218: new Class[0]);
219: int labelId = 1;
220: for (int classIdx = 0; classIdx < _clazzes.length; classIdx++) {
221: builder
222: .invokeLoadClassConstMethod(convertToArray(_clazzes[classIdx]));
223: builder.aload(1);
224: builder.invokeVirtual(Type.CLASS, "isAssignableFrom",
225: new Type[] { Type.CLASS }, Type.BOOLEAN);
226: builder.ifeq(labelId);
227: builder.invokeLoadClassConstMethod(_clazzes[classIdx]);
228: builder.areturn();
229: builder.label(labelId);
230: labelId++;
231: }
232: builder.aload(0);
233: builder.aload(1);
234: builder
235: .invokeSpecial(
236: _context
237: .getType(com.db4o.reflect.self.SelfReflectionRegistry.class),
238: COMPONENTTYPE_METHODNAME,
239: new Type[] { Type.CLASS }, Type.CLASS);
240: builder.areturn();
241: builder.commit();
242:
243: }
244:
245: private Class convertToArray(Class clazz) {
246: return Array.newInstance(clazz, new int[1]).getClass();
247: }
248:
249: }
|