KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > objectserver > managedobject > bytecode > PhysicalStateClassLoader


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.objectserver.managedobject.bytecode;
5
6 import com.tc.asm.ClassWriter;
7 import com.tc.asm.FieldVisitor;
8 import com.tc.asm.Label;
9 import com.tc.asm.MethodVisitor;
10 import com.tc.asm.Opcodes;
11 import com.tc.exception.TCRuntimeException;
12 import com.tc.object.LiteralValues;
13 import com.tc.object.ObjectID;
14 import com.tc.util.AdaptedClassDumper;
15
16 import java.util.ArrayList JavaDoc;
17 import java.util.Collections JavaDoc;
18 import java.util.HashMap JavaDoc;
19 import java.util.Iterator JavaDoc;
20 import java.util.List JavaDoc;
21 import java.util.Map JavaDoc;
22
23 public class PhysicalStateClassLoader extends ClassLoader JavaDoc implements Opcodes {
24
25   public static class MethodDetail {
26
27     private final String JavaDoc methodName;
28     private final String JavaDoc methodDesc;
29
30     public MethodDetail(String JavaDoc methodName, String JavaDoc methodDesc) {
31       this.methodName = methodName;
32       this.methodDesc = methodDesc;
33     }
34
35     public String JavaDoc getMethodDescriptor() {
36       return methodDesc;
37     }
38
39     public String JavaDoc getMethodName() {
40       return methodName;
41     }
42
43   }
44
45   private static final String JavaDoc PARENT_ID_FIELD = "parentId";
46
47   private static final Map JavaDoc OBJECT_OUTPUT_METHODS = Collections.synchronizedMap(new HashMap JavaDoc());
48   private static final Map JavaDoc OBJECT_INPUT_METHODS = Collections.synchronizedMap(new HashMap JavaDoc());
49
50   static {
51     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.INTEGER, "writeInt", "(I)V");
52     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.LONG, "writeLong", "(J)V");
53     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.CHARACTER, "writeChar", "(I)V");
54     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.BYTE, "writeByte", "(I)V");
55     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.SHORT, "writeShort", "(I)V");
56     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.FLOAT, "writeFloat", "(F)V");
57     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.DOUBLE, "writeDouble", "(D)V");
58     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.BOOLEAN, "writeBoolean", "(Z)V");
59     // rest are written as Objects - Since we use TCObjectOutputStream, we optimize it there.
60
addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.OBJECT, "writeObject", "(Ljava/lang/Object;)V");
61     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.OBJECT_ID, "writeObject", "(Ljava/lang/Object;)V");
62     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.ARRAY, "writeObject", "(Ljava/lang/Object;)V");
63     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.JAVA_LANG_CLASS, "writeObject", "(Ljava/lang/Object;)V");
64     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.JAVA_LANG_CLASS_HOLDER, "writeObject", "(Ljava/lang/Object;)V");
65     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.STACK_TRACE_ELEMENT, "writeObject", "(Ljava/lang/Object;)V");
66     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.STRING, "writeObject", "(Ljava/lang/Object;)V");
67     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.STRING_BYTES, "writeObject", "(Ljava/lang/Object;)V");
68     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.BIG_INTEGER, "writeObject", "(Ljava/lang/Object;)V");
69     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.BIG_DECIMAL, "writeObject", "(Ljava/lang/Object;)V");
70     
71     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.JAVA_LANG_CLASSLOADER, "writeObject", "(Ljava/lang/Object;)V");
72     addMapping(OBJECT_OUTPUT_METHODS, LiteralValues.JAVA_LANG_CLASSLOADER_HOLDER, "writeObject", "(Ljava/lang/Object;)V");
73
74
75     addMapping(OBJECT_INPUT_METHODS, LiteralValues.INTEGER, "readInt", "()I");
76     addMapping(OBJECT_INPUT_METHODS, LiteralValues.LONG, "readLong", "()J");
77     addMapping(OBJECT_INPUT_METHODS, LiteralValues.CHARACTER, "readChar", "()C");
78     addMapping(OBJECT_INPUT_METHODS, LiteralValues.BYTE, "readByte", "()B");
79     addMapping(OBJECT_INPUT_METHODS, LiteralValues.SHORT, "readShort", "()S");
80     addMapping(OBJECT_INPUT_METHODS, LiteralValues.FLOAT, "readFloat", "()F");
81     addMapping(OBJECT_INPUT_METHODS, LiteralValues.DOUBLE, "readDouble", "()D");
82     addMapping(OBJECT_INPUT_METHODS, LiteralValues.BOOLEAN, "readBoolean", "()Z");
83     // rest are read as Objects - Since we use TCObjectInputStream, we optimize it there.
84
addMapping(OBJECT_INPUT_METHODS, LiteralValues.OBJECT, "readObject", "()Ljava/lang/Object;");
85     addMapping(OBJECT_INPUT_METHODS, LiteralValues.OBJECT_ID, "readObject", "()Ljava/lang/Object;");
86     addMapping(OBJECT_INPUT_METHODS, LiteralValues.ARRAY, "readObject", "()Ljava/lang/Object;");
87     addMapping(OBJECT_INPUT_METHODS, LiteralValues.JAVA_LANG_CLASS, "readObject", "()Ljava/lang/Object;");
88     addMapping(OBJECT_INPUT_METHODS, LiteralValues.JAVA_LANG_CLASS_HOLDER, "readObject", "()Ljava/lang/Object;");
89     addMapping(OBJECT_INPUT_METHODS, LiteralValues.STACK_TRACE_ELEMENT, "readObject", "()Ljava/lang/Object;");
90     addMapping(OBJECT_INPUT_METHODS, LiteralValues.STRING, "readObject", "()Ljava/lang/Object;");
91     addMapping(OBJECT_INPUT_METHODS, LiteralValues.STRING_BYTES, "readObject", "()Ljava/lang/Object;");
92     addMapping(OBJECT_INPUT_METHODS, LiteralValues.BIG_INTEGER, "readObject", "()Ljava/lang/Object;");
93     addMapping(OBJECT_INPUT_METHODS, LiteralValues.BIG_DECIMAL, "readObject", "()Ljava/lang/Object;");
94     
95     addMapping(OBJECT_INPUT_METHODS, LiteralValues.JAVA_LANG_CLASSLOADER, "readObject", "()Ljava/lang/Object;");
96     addMapping(OBJECT_INPUT_METHODS, LiteralValues.JAVA_LANG_CLASSLOADER_HOLDER, "readObject", "()Ljava/lang/Object;");
97
98     
99   }
100
101   public PhysicalStateClassLoader(ClassLoader JavaDoc parent) {
102     super(parent);
103   }
104
105   private static void addMapping(Map JavaDoc map, int type, String JavaDoc methodName, String JavaDoc methodDesc) {
106     map.put(new Integer JavaDoc(type), new MethodDetail(methodName, methodDesc));
107   }
108
109   private static MethodDetail get(Map JavaDoc map, int type) {
110     MethodDetail md = (MethodDetail) map.get(new Integer JavaDoc(type));
111     if (md == null) { throw new TCRuntimeException("Unknown Type : " + type + " Map = " + map); }
112     return md;
113   }
114
115   public PhysicalStateClassLoader() {
116     super();
117   }
118
119   public byte[] createClassBytes(ClassSpec cs, ObjectID parentID, List JavaDoc fields) {
120     byte data[] = basicCreateClassBytes(cs, parentID, fields);
121     AdaptedClassDumper.write(cs.getGeneratedClassName(), data);
122     return data;
123   }
124
125   public Class JavaDoc defineClassFromBytes(String JavaDoc className, int classId, byte[] clazzBytes, int offset, int length) {
126     Class JavaDoc clazz = defineClass(className, clazzBytes, offset, length);
127     return clazz;
128   }
129
130   private byte[] basicCreateClassBytes(ClassSpec cs, ObjectID parentID, List JavaDoc fields) {
131     String JavaDoc classNameSlash = cs.getGeneratedClassName().replace('.', '/');
132     String JavaDoc superClassNameSlash = cs.getSuperClassName().replace('.', '/');
133     ClassWriter cw = new ClassWriter(false);
134
135     cw.visit(V1_2, ACC_PUBLIC | ACC_SUPER, classNameSlash, null, superClassNameSlash, null);
136
137     createConstructor(cw, superClassNameSlash);
138     if (!parentID.isNull()) {
139       createParentIDField(cw);
140       createGetParentIDMethod(cw, classNameSlash);
141       createSetParentIDMethod(cw, classNameSlash);
142     }
143
144     createFields(cw, fields);
145     createGetClassNameMethod(cw, classNameSlash, cs);
146     createGetLoaderDescriptionMethod(cw, classNameSlash, cs);
147     createGetObjectReferencesMethod(cw, classNameSlash, parentID, cs, superClassNameSlash, fields);
148     createBasicSetMethod(cw, classNameSlash, cs, superClassNameSlash, fields);
149     createBasicDehydrateMethod(cw, classNameSlash, cs, superClassNameSlash, fields);
150     createAddValuesMethod(cw, classNameSlash, cs, superClassNameSlash, fields);
151     createWriteObjectMethod(cw, classNameSlash, cs, superClassNameSlash, fields);
152     createReadObjectMethod(cw, classNameSlash, cs, superClassNameSlash, fields);
153
154     createGetClassIdMethod(cw, classNameSlash, cs);
155
156     cw.visitEnd();
157     return cw.toByteArray();
158   }
159
160   // *************************************************************************************
161
// The Code generated by this method looks (kind of) this.
162
//
163
// public String getLoaderDescription() {
164
// return "System.ext";
165
// }
166
// *************************************************************************************
167
private void createGetLoaderDescriptionMethod(ClassWriter cw, String JavaDoc classNameSlash, ClassSpec cs) {
168     if (!cs.isDirectSubClassOfPhysicalMOState()) {
169       // We dont have to regenerate this method as the super class would have it.
170
return;
171     }
172     MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "getLoaderDescription", "()Ljava/lang/String;", null, null);
173     mv.visitCode();
174     mv.visitLdcInsn(cs.getLoaderDesc());
175     mv.visitInsn(ARETURN);
176     mv.visitMaxs(1, 1);
177     mv.visitEnd();
178   }
179
180   // *************************************************************************************
181
// The Code generated by this method looks (kind of) this.
182
//
183
// public String getClassName() {
184
// return "com.tc.className";
185
// }
186
// *************************************************************************************
187
private void createGetClassNameMethod(ClassWriter cw, String JavaDoc classNameSlash, ClassSpec cs) {
188     if (!cs.isDirectSubClassOfPhysicalMOState()) {
189       // We dont have to regenerate this method as the super class would have it.
190
return;
191     }
192     MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "getClassName", "()Ljava/lang/String;", null, null);
193     mv.visitCode();
194     mv.visitLdcInsn(cs.getClassName());
195     mv.visitInsn(ARETURN);
196     mv.visitMaxs(1, 1);
197     mv.visitEnd();
198   }
199
200   // *************************************************************************************
201
// The Code generated by this method looks (kind of) this.
202
//
203
// protected int getClassId() {
204
// return 8;
205
// }
206
// *************************************************************************************
207
private void createGetClassIdMethod(ClassWriter cw, String JavaDoc classNameSlash, ClassSpec cs) {
208     MethodVisitor mv = cw.visitMethod(ACC_PROTECTED, "getClassId", "()I", null, null);
209     mv.visitLdcInsn(new Integer JavaDoc(cs.getClassID()));
210     mv.visitInsn(IRETURN);
211     mv.visitMaxs(1, 1);
212     mv.visitEnd();
213   }
214
215   // *************************************************************************************
216
// The Code generated by this method looks (kind of) this.
217
//
218
// long x;
219
// Object o;
220
// char c;
221
// public void writeObject(ObjectOutput out) throws IOException {
222
// out.writeLong(x);
223
// out.writeObject(o);
224
// out.writeChar(c);
225
// }
226
// *************************************************************************************
227
private void createWriteObjectMethod(ClassWriter cw, String JavaDoc classNameSlash, ClassSpec cs, String JavaDoc superClassNameSlash, List JavaDoc fields) {
228     MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "writeObject", "(Ljava/io/ObjectOutput;)V", null,
229                                       new String JavaDoc[] { "java/io/IOException" });
230     mv.visitCode();
231     
232     if (!cs.isDirectSubClassOfPhysicalMOState()) {
233       mv.visitVarInsn(ALOAD, 0);
234       mv.visitVarInsn(ALOAD, 1);
235       mv.visitMethodInsn(INVOKESPECIAL, superClassNameSlash, "writeObject", "(Ljava/io/ObjectOutput;)V");
236     }
237
238     for (Iterator JavaDoc i = fields.iterator(); i.hasNext();) {
239       FieldType f = (FieldType) i.next();
240       mv.visitVarInsn(ALOAD, 1);
241       mv.visitVarInsn(ALOAD, 0);
242       mv.visitFieldInsn(GETFIELD, classNameSlash, f.getLocalFieldName(), getFieldTypeDesc(f.getType()));
243       MethodDetail md = get(OBJECT_OUTPUT_METHODS, f.getType());
244       mv.visitMethodInsn(INVOKEINTERFACE, "java/io/ObjectOutput", md.getMethodName(), md.getMethodDescriptor());
245     }
246     mv.visitInsn(RETURN);
247     mv.visitMaxs(3, 2);
248     mv.visitEnd();
249   }
250
251   // *************************************************************************************
252
// The Code generated by this method looks (kind of) this.
253
//
254
// long x;
255
// Object o;
256
// char c;
257
//
258
// public void readObject(ObjectInput in) throws IOException, ClassNotFoundException {
259
// x = in.readLong();
260
// o = in.readObject();
261
// c = in.readChar();
262
// }
263
// *************************************************************************************
264
private void createReadObjectMethod(ClassWriter cw, String JavaDoc classNameSlash, ClassSpec cs, String JavaDoc superClassNameSlash, List JavaDoc fields) {
265     MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "readObject", "(Ljava/io/ObjectInput;)V", null, new String JavaDoc[] {
266         "java/io/IOException", "java/lang/ClassNotFoundException" });
267     mv.visitCode();
268
269     if (!cs.isDirectSubClassOfPhysicalMOState()) {
270       mv.visitVarInsn(ALOAD, 0);
271       mv.visitVarInsn(ALOAD, 1);
272       mv.visitMethodInsn(INVOKESPECIAL, superClassNameSlash, "readObject", "(Ljava/io/ObjectInput;)V");
273     }
274     
275     for (Iterator JavaDoc i = fields.iterator(); i.hasNext();) {
276       FieldType f = (FieldType) i.next();
277       mv.visitVarInsn(ALOAD, 0);
278       mv.visitVarInsn(ALOAD, 1);
279       MethodDetail md = get(OBJECT_INPUT_METHODS, f.getType());
280       mv.visitMethodInsn(INVOKEINTERFACE, "java/io/ObjectInput", md.getMethodName(), md.getMethodDescriptor());
281       mv.visitFieldInsn(PUTFIELD, classNameSlash, f.getLocalFieldName(), getFieldTypeDesc(f.getType()));
282     }
283     mv.visitInsn(RETURN);
284     mv.visitMaxs(3, 2);
285     mv.visitEnd();
286   }
287
288   // *************************************************************************************
289
// The Code generated by this method looks (kind of) this.
290
//
291
// long x;
292
// Object o;
293
// public Map addValues(Map map) {
294
// map.put("x", new Long(x));
295
// map.put("o", o);
296
// return map;
297
// }
298
// *************************************************************************************
299
private void createAddValuesMethod(ClassWriter cw, String JavaDoc classNameSlash, ClassSpec cs, String JavaDoc superClassNameSlash,
300                                      List JavaDoc fields) {
301     MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "addValues", "(Ljava/util/Map;)Ljava/util/Map;", null, null);
302     mv.visitCode();
303
304     if (!cs.isDirectSubClassOfPhysicalMOState()) {
305       mv.visitVarInsn(ALOAD, 0);
306       mv.visitVarInsn(ALOAD, 1);
307       mv.visitMethodInsn(INVOKESPECIAL, superClassNameSlash, "addValues", "(Ljava/util/Map;)Ljava/util/Map;");
308       mv.visitInsn(POP);
309     }
310
311     for (Iterator JavaDoc i = fields.iterator(); i.hasNext();) {
312       FieldType f = (FieldType) i.next();
313       mv.visitVarInsn(ALOAD, 1);
314       mv.visitLdcInsn(f.getQualifiedName());
315       getObjectFor(mv, classNameSlash, f);
316       mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "put",
317                          "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
318       mv.visitInsn(POP);
319     }
320     mv.visitVarInsn(ALOAD, 1);
321     mv.visitInsn(ARETURN);
322
323     mv.visitMaxs(6, 2);
324     mv.visitEnd();
325
326   }
327
328   // *************************************************************************************
329
// The Code generated by this method looks (kind of) this.
330
//
331
// long x;
332
// Object o;
333
// protected void basicDehydrate(DNAWriter writer) {
334
// writer.addPhysicalAction("x", new Long(x));
335
// writer.addPhysicalAction("o", o);
336
// }
337
// *************************************************************************************
338
private void createBasicDehydrateMethod(ClassWriter cw, String JavaDoc classNameSlash, ClassSpec cs,
339                                           String JavaDoc superClassNameSlash, List JavaDoc fields) {
340     MethodVisitor mv = cw.visitMethod(ACC_PROTECTED, "basicDehydrate", "(Lcom/tc/object/dna/api/DNAWriter;)V", null,
341                                       null);
342     mv.visitCode();
343
344     if (!cs.isDirectSubClassOfPhysicalMOState()) {
345       mv.visitVarInsn(ALOAD, 0);
346       mv.visitVarInsn(ALOAD, 1);
347       mv.visitMethodInsn(INVOKESPECIAL, superClassNameSlash, "basicDehydrate", "(Lcom/tc/object/dna/api/DNAWriter;)V");
348     }
349
350     for (Iterator JavaDoc i = fields.iterator(); i.hasNext();) {
351       FieldType f = (FieldType) i.next();
352       mv.visitVarInsn(ALOAD, 1);
353       mv.visitLdcInsn(f.getQualifiedName());
354       getObjectFor(mv, classNameSlash, f);
355       // TODO:: May be we shouldnt call DNAWriter methods from instrumented code !
356
mv.visitMethodInsn(INVOKEINTERFACE, "com/tc/object/dna/api/DNAWriter", "addPhysicalAction",
357                          "(Ljava/lang/String;Ljava/lang/Object;)V");
358     }
359     mv.visitInsn(RETURN);
360
361     mv.visitMaxs(6, 2);
362     mv.visitEnd();
363   }
364
365   // *************************************************************************************
366
// The Code generated by this method looks (kind of) this.
367
//
368
// long x;
369
// Object o;
370
// protected Object basicSet(String f, Object value) {
371
// if ("x".equals(f)) {
372
// Object old = new Long(x);
373
// x = ((Long) value).longValue();
374
// return old;
375
// }
376
// if("o".equals(f)) {
377
// Object old = o;
378
// o = value;
379
// return old;
380
// }
381
// throw new ClassNotCompatableException("Not found ! field = " + f + " value = " + value);
382
// }
383
// *************************************************************************************
384
private void createBasicSetMethod(ClassWriter cw, String JavaDoc classNameSlash, ClassSpec cs, String JavaDoc superClassNameSlash,
385                                     List JavaDoc fields) {
386     MethodVisitor mv = cw.visitMethod(ACC_PROTECTED, "basicSet",
387                                       "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;", null, null);
388     mv.visitCode();
389
390     for (Iterator JavaDoc i = fields.iterator(); i.hasNext();) {
391       FieldType f = (FieldType) i.next();
392       mv.visitLdcInsn(f.getQualifiedName());
393       mv.visitVarInsn(ALOAD, 1);
394       mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
395       Label l1 = new Label();
396       mv.visitJumpInsn(IFEQ, l1);
397       getObjectFor(mv, classNameSlash, f);
398       mv.visitVarInsn(ASTORE, 3);
399       mv.visitVarInsn(ALOAD, 0);
400       mv.visitVarInsn(ALOAD, 2);
401       getValueFrom(mv, classNameSlash, f);
402       mv.visitFieldInsn(PUTFIELD, classNameSlash, f.getLocalFieldName(), getFieldTypeDesc(f.getType()));
403       mv.visitVarInsn(ALOAD, 3);
404       mv.visitInsn(ARETURN);
405       mv.visitLabel(l1);
406     }
407
408     if (cs.isDirectSubClassOfPhysicalMOState()) {
409       // throw Assertion Error
410
mv.visitTypeInsn(NEW, "com/tc/objectserver/managedobject/bytecode/ClassNotCompatableException");
411       mv.visitInsn(DUP);
412       mv.visitTypeInsn(NEW, "java/lang/StringBuffer");
413       mv.visitInsn(DUP);
414       mv.visitLdcInsn("Not found ! field = ");
415       mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "(Ljava/lang/String;)V");
416       mv.visitVarInsn(ALOAD, 1);
417       mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append",
418                          "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
419       mv.visitLdcInsn(" value = ");
420       mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append",
421                          "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
422       mv.visitVarInsn(ALOAD, 2);
423       mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append",
424                          "(Ljava/lang/Object;)Ljava/lang/StringBuffer;");
425       mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "toString", "()Ljava/lang/String;");
426       mv.visitMethodInsn(INVOKESPECIAL, "com/tc/objectserver/managedobject/bytecode/ClassNotCompatableException",
427                          "<init>", "(Ljava/lang/String;)V");
428       mv.visitInsn(ATHROW);
429     } else {
430       // Call super class's implementation
431
mv.visitVarInsn(ALOAD, 0);
432       mv.visitVarInsn(ALOAD, 1);
433       mv.visitVarInsn(ALOAD, 2);
434       mv.visitMethodInsn(INVOKESPECIAL, superClassNameSlash, "basicSet",
435                          "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;");
436       mv.visitInsn(ARETURN);
437     }
438
439     mv.visitMaxs(5, 4);
440     mv.visitEnd();
441   }
442
443   /**
444    * This method generates code to the object reference from the top of the stack and convert it into a primitive type
445    * (if needed) and leave that value in the top of the stack.
446    */

447   private void getValueFrom(MethodVisitor mv, String JavaDoc classNameSlash, FieldType f) {
448     String JavaDoc classOnStack = getClassNameFor(f.getType());
449     if ("java/lang/Object".equals(classOnStack)) { return; }
450     mv.visitTypeInsn(CHECKCAST, classOnStack);
451     mv.visitMethodInsn(INVOKEVIRTUAL, classOnStack, getMethodNameForPrimitives(f.getType()), "()"
452                                                                                              + getFieldTypeDesc((f
453                                                                                                  .getType())));
454
455   }
456
457   /**
458    * This method generates code so that the object equivalent of the field is left on the stack.
459    */

460   private void getObjectFor(MethodVisitor mv, String JavaDoc classNameSlash, FieldType f) {
461     String JavaDoc classToReturn = getClassNameFor(f.getType());
462     if ("java/lang/Object".equals(classToReturn)) {
463       mv.visitVarInsn(ALOAD, 0);
464       mv.visitFieldInsn(GETFIELD, classNameSlash, f.getLocalFieldName(), getFieldTypeDesc(f.getType()));
465       return;
466     }
467     String JavaDoc fieldTypeDesc = getFieldTypeDesc(f.getType());
468     String JavaDoc constructorDesc = "(" + fieldTypeDesc + ")V";
469     mv.visitTypeInsn(NEW, classToReturn);
470     mv.visitInsn(DUP);
471     mv.visitVarInsn(ALOAD, 0);
472     mv.visitFieldInsn(GETFIELD, classNameSlash, f.getLocalFieldName(), fieldTypeDesc);
473     mv.visitMethodInsn(INVOKESPECIAL, classToReturn, "<init>", constructorDesc);
474
475   }
476
477   // *************************************************************************************
478
// The Code generated by this method looks (kind of) this.
479
//
480
// private Object oid1;
481
// public Set getObjectReferences() {
482
// Set result = new THashSet(25);
483
// if (oid1 instanceof ObjectID && !((ObjectID)oid1).isNull() ) {
484
// result.add(oid1);
485
// }
486
// return result;
487
// }
488
// *************************************************************************************
489
private void createGetObjectReferencesMethod(ClassWriter cw, String JavaDoc classNameSlash, ObjectID parentID, ClassSpec cs,
490                                                String JavaDoc superClassNameSlash, List JavaDoc fields) {
491     List JavaDoc referenceFields = new ArrayList JavaDoc(fields.size());
492     for (Iterator JavaDoc i = fields.iterator(); i.hasNext();) {
493       FieldType f = (FieldType) i.next();
494       if (f.getType() == LiteralValues.OBJECT_ID) {
495         referenceFields.add(f);
496       }
497     }
498
499     // There is no references in this object and it is not a direct subclass of Physical Managed Object State
500
if (referenceFields.size() == 0 && parentID.isNull() && !cs.isDirectSubClassOfPhysicalMOState()) {
501       // The parent object has the necessary implementations
502
return;
503     }
504
505     MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "getObjectReferences", "()Ljava/util/Set;", null, null);
506     mv.visitCode();
507
508     // There is no references in this object
509
if (referenceFields.size() == 0 && parentID.isNull()) {
510       mv.visitFieldInsn(GETSTATIC, "java/util/Collections", "EMPTY_SET", "Ljava/util/Set;");
511       mv.visitInsn(ARETURN);
512       mv.visitMaxs(1, 1);
513       mv.visitEnd();
514       return;
515     }
516
517     int size = referenceFields.size();
518     if (!parentID.isNull() && cs.isDirectSubClassOfPhysicalMOState()) {
519       size++;
520     }
521
522     mv.visitTypeInsn(NEW, "gnu/trove/THashSet");
523     mv.visitInsn(DUP);
524     mv.visitIntInsn(BIPUSH, size);
525     mv.visitMethodInsn(INVOKESPECIAL, "gnu/trove/THashSet", "<init>", "(I)V");
526     mv.visitVarInsn(ASTORE, 1);
527
528     if (!cs.isDirectSubClassOfPhysicalMOState()) {
529       mv.visitVarInsn(ALOAD, 0);
530       mv.visitMethodInsn(INVOKESPECIAL, superClassNameSlash, "getObjectReferences", "()Ljava/util/Set;");
531       mv.visitVarInsn(ASTORE, 2);
532       mv.visitVarInsn(ALOAD, 1);
533       mv.visitVarInsn(ALOAD, 2);
534       mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Set", "addAll", "(Ljava/util/Collection;)Z");
535       mv.visitInsn(POP);
536     }
537
538     for (Iterator JavaDoc i = referenceFields.iterator(); i.hasNext();) {
539       FieldType f = (FieldType) i.next();
540       mv.visitVarInsn(ALOAD, 0);
541       mv.visitFieldInsn(GETFIELD, classNameSlash, f.getLocalFieldName(), getFieldTypeDesc(f.getType()));
542       mv.visitTypeInsn(INSTANCEOF, "com/tc/object/ObjectID");
543       Label l2 = new Label();
544       mv.visitJumpInsn(IFEQ, l2);
545       mv.visitVarInsn(ALOAD, 0);
546       mv.visitFieldInsn(GETFIELD, classNameSlash, f.getLocalFieldName(), getFieldTypeDesc(f.getType()));
547       mv.visitTypeInsn(CHECKCAST, "com/tc/object/ObjectID");
548       mv.visitMethodInsn(INVOKEVIRTUAL, "com/tc/object/ObjectID", "isNull", "()Z");
549       mv.visitJumpInsn(IFNE, l2);
550       mv.visitVarInsn(ALOAD, 1);
551       mv.visitVarInsn(ALOAD, 0);
552       mv.visitFieldInsn(GETFIELD, classNameSlash, f.getLocalFieldName(), getFieldTypeDesc(f.getType()));
553       mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Set", "add", "(Ljava/lang/Object;)Z");
554       mv.visitInsn(POP);
555       mv.visitLabel(l2);
556     }
557     if (!parentID.isNull() && cs.isDirectSubClassOfPhysicalMOState()) {
558       // add parentID too
559
mv.visitVarInsn(ALOAD, 1);
560       mv.visitVarInsn(ALOAD, 0);
561       mv.visitFieldInsn(GETFIELD, classNameSlash, PARENT_ID_FIELD, "Lcom/tc/object/ObjectID;");
562       mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Set", "add", "(Ljava/lang/Object;)Z");
563       mv.visitInsn(POP);
564     }
565     mv.visitVarInsn(ALOAD, 1);
566     mv.visitInsn(ARETURN);
567     mv.visitMaxs(3, 3);
568     mv.visitEnd();
569   }
570
571   private void createFields(ClassWriter cw, List JavaDoc fields) {
572     for (Iterator JavaDoc i = fields.iterator(); i.hasNext();) {
573       FieldType f = (FieldType) i.next();
574       FieldVisitor fv = cw.visitField(ACC_PRIVATE, f.getLocalFieldName(), getFieldTypeDesc(f.getType()), null, null);
575       fv.visitEnd();
576     }
577   }
578
579   private String JavaDoc getFieldTypeDesc(int type) {
580     switch (type) {
581       case LiteralValues.INTEGER:
582         return "I";
583       case LiteralValues.LONG:
584         return "J";
585       case LiteralValues.CHARACTER:
586         return "C";
587       case LiteralValues.FLOAT:
588         return "F";
589       case LiteralValues.DOUBLE:
590         return "D";
591       case LiteralValues.BYTE:
592         return "B";
593       case LiteralValues.SHORT:
594         return "S";
595       case LiteralValues.BOOLEAN:
596         return "Z";
597       case LiteralValues.OBJECT_ID:
598         return "Ljava/lang/Object;"; // ObjectIDs are NOT stored as longs anymore :(
599
default:
600         return "Ljava/lang/Object;"; // Everything else is stored as Object reference
601
}
602   }
603
604   // TODO:: Clean up to use MethodDetail class
605
private String JavaDoc getMethodNameForPrimitives(int type) {
606     switch (type) {
607       case LiteralValues.INTEGER:
608         return "intValue";
609       case LiteralValues.LONG:
610         return "longValue";
611       case LiteralValues.CHARACTER:
612         return "charValue";
613       case LiteralValues.FLOAT:
614         return "floatValue";
615       case LiteralValues.DOUBLE:
616         return "doubleValue";
617       case LiteralValues.BYTE:
618         return "byteValue";
619       case LiteralValues.SHORT:
620         return "shortValue";
621       case LiteralValues.BOOLEAN:
622         return "booleanValue";
623       // ObjectIDs are NOT stored as longs anymore :(
624
// case LiteralValues.OBJECT_ID:
625
// return "toLong";
626
default:
627         throw new AssertionError JavaDoc("This type is invalid : " + type);
628     }
629   }
630
631   private String JavaDoc getClassNameFor(int type) {
632     switch (type) {
633       case LiteralValues.INTEGER:
634         return "java/lang/Integer";
635       case LiteralValues.LONG:
636         return "java/lang/Long";
637       case LiteralValues.CHARACTER:
638         return "java/lang/Character";
639       case LiteralValues.FLOAT:
640         return "java/lang/Float";
641       case LiteralValues.DOUBLE:
642         return "java/lang/Double";
643       case LiteralValues.BYTE:
644         return "java/lang/Byte";
645       case LiteralValues.SHORT:
646         return "java/lang/Short";
647       case LiteralValues.BOOLEAN:
648         return "java/lang/Boolean";
649       case LiteralValues.OBJECT_ID:
650         return "java/lang/Object"; // ObjectIDs are NOT stored as longs anymore :(
651
default:
652         return "java/lang/Object"; // Everything else is stored as Object reference
653
}
654   }
655
656   private void createParentIDField(ClassWriter cw) {
657     FieldVisitor fv = cw.visitField(ACC_PRIVATE, PARENT_ID_FIELD, "Lcom/tc/object/ObjectID;", null, null);
658     fv.visitEnd();
659   }
660
661   // *************************************************************************************
662
// The Code generated by this method looks (kind of) this.
663
//
664
// ObjectID parentId;
665
// public ObjectID getParentID() {
666
// return parentId;
667
// }
668
// *************************************************************************************
669
private void createGetParentIDMethod(ClassWriter cw, String JavaDoc classNameSlash) {
670     MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "getParentID", "()Lcom/tc/object/ObjectID;", null, null);
671     mv.visitCode();
672     mv.visitVarInsn(ALOAD, 0);
673     mv.visitFieldInsn(GETFIELD, classNameSlash, PARENT_ID_FIELD, "Lcom/tc/object/ObjectID;");
674     mv.visitInsn(ARETURN);
675     mv.visitMaxs(2, 1);
676     mv.visitEnd();
677   }
678
679   // *************************************************************************************
680
// The Code generated by this method looks (kind of) this.
681
//
682
// ObjectID parentId;
683
// public void setParentID(ObjectID id) {
684
// parentId = id;
685
// }
686
// *************************************************************************************
687
private void createSetParentIDMethod(ClassWriter cw, String JavaDoc classNameSlash) {
688     MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "setParentID", "(Lcom/tc/object/ObjectID;)V", null, null);
689     mv.visitCode();
690     mv.visitVarInsn(ALOAD, 0);
691     mv.visitVarInsn(ALOAD, 1);
692     mv.visitFieldInsn(PUTFIELD, classNameSlash, PARENT_ID_FIELD, "Lcom/tc/object/ObjectID;");
693     mv.visitInsn(RETURN);
694     mv.visitMaxs(3, 2);
695     mv.visitEnd();
696   }
697
698   private void createConstructor(ClassWriter cw, String JavaDoc superClassNameSlash) {
699     MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
700     mv.visitCode();
701     mv.visitVarInsn(ALOAD, 0);
702     mv.visitMethodInsn(INVOKESPECIAL, superClassNameSlash, "<init>", "()V");
703     mv.visitInsn(RETURN);
704     mv.visitMaxs(2, 2);
705     mv.visitEnd();
706   }
707
708 }
709
Popular Tags