KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > fractal > adl > NodeClassLoader


1 /***
2  * Fractal ADL Parser
3  * Copyright (C) 2002-2004 France Telecom R&D
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Contact: Eric.Bruneton@rd.francetelecom.com
20  *
21  * Author: Eric Bruneton
22  */

23
24 package org.objectweb.fractal.adl;
25
26 import java.io.ByteArrayInputStream JavaDoc;
27 import java.io.InputStream JavaDoc;
28 import java.lang.reflect.Method JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.HashSet JavaDoc;
31 import java.util.Map JavaDoc;
32 import java.util.Set JavaDoc;
33
34 import org.objectweb.asm.ClassWriter;
35 import org.objectweb.asm.CodeVisitor;
36 import org.objectweb.asm.Constants;
37 import org.objectweb.asm.Label;
38 import org.objectweb.asm.Type;
39
40 /**
41  * An abstract class loader to dynamically generate {@link Node} classes.
42  */

43
44 public abstract class NodeClassLoader extends ClassLoader JavaDoc implements Constants {
45   
46   /**
47    * Byte code of the dynamically generated classes.
48    */

49
50   private Map JavaDoc bytecodes = new HashMap JavaDoc();
51     
52   public NodeClassLoader (final ClassLoader JavaDoc parent) {
53     super(parent);
54   }
55   
56   public ClassWriter generateClass (
57     final String JavaDoc className,
58     final String JavaDoc astNodeName,
59     final String JavaDoc superClass,
60     final String JavaDoc[] itfs) throws ClassNotFoundException JavaDoc
61   {
62     String JavaDoc owner = className.replace('.', '/');
63     String JavaDoc node = Type.getInternalName(Node.class);
64
65     ClassWriter cw = new ClassWriter(true);
66     cw.visit(V1_1, ACC_PUBLIC, owner, superClass, itfs, null);
67
68     CodeVisitor icv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
69     icv.visitVarInsn(ALOAD, 0);
70     icv.visitLdcInsn(astNodeName);
71     icv.visitMethodInsn(INVOKESPECIAL, superClass, "<init>", "(Ljava/lang/String;)V");
72
73     CodeVisitor ani = cw.visitMethod(
74         ACC_PUBLIC, "astNewInstance", "()L" + node + ";", null, null);
75     ani.visitTypeInsn(NEW, owner);
76     ani.visitInsn(DUP);
77     ani.visitMethodInsn(INVOKESPECIAL, owner, "<init>", "()V");
78     ani.visitInsn(ARETURN);
79     ani.visitMaxs(0, 0);
80     
81     CodeVisitor aga = cw.visitMethod(
82         ACC_PUBLIC, "astGetAttributes", "()Ljava/util/Map;", null, null);
83     aga.visitTypeInsn(NEW, "java/util/HashMap");
84     aga.visitInsn(DUP);
85     aga.visitMethodInsn(INVOKESPECIAL, "java/util/HashMap", "<init>", "()V");
86     aga.visitVarInsn(ASTORE, 1);
87
88     CodeVisitor asa = cw.visitMethod(
89         ACC_PUBLIC, "astSetAttributes", "(Ljava/util/Map;)V", null, null);
90
91     CodeVisitor agn = cw.visitMethod(
92         ACC_PUBLIC, "astGetNodeTypes", "()[Ljava/lang/String;", null, null);
93     agn.visitIntInsn(SIPUSH, getNodeCount(itfs));
94     agn.visitTypeInsn(ANEWARRAY, "java/lang/String");
95
96     CodeVisitor agns = cw.visitMethod(
97         ACC_PUBLIC, "astGetNodes", "(Ljava/lang/String;)[L" + node + ";", null, null);
98     Label agnsEnd = new Label();
99     agns.visitInsn(ACONST_NULL);
100     agns.visitVarInsn(ASTORE, 2);
101
102     CodeVisitor aan = cw.visitMethod(
103         ACC_PUBLIC, "astAddNode", "(L" + node + ";)V", null, null);
104     aan.visitVarInsn(ALOAD, 1);
105     aan.visitMethodInsn(
106       INVOKEINTERFACE,
107       "org/objectweb/fractal/adl/Node",
108       "astGetType",
109       "()Ljava/lang/String;");
110     aan.visitVarInsn(ASTORE, 2);
111     Label aanEnd = new Label();
112
113     CodeVisitor arn = cw.visitMethod(
114         ACC_PUBLIC, "astRemoveNode", "(L" + node + ";)V", null, null);
115     arn.visitVarInsn(ALOAD, 1);
116     arn.visitMethodInsn(
117       INVOKEINTERFACE,
118       "org/objectweb/fractal/adl/Node",
119       "astGetType",
120       "()Ljava/lang/String;");
121     arn.visitVarInsn(ASTORE, 2);
122     Label arnEnd = new Label();
123
124     int count = 0;
125     Set JavaDoc methods = new HashSet JavaDoc();
126     for (int i = 0; i < itfs.length; ++i) {
127       Method JavaDoc[] meths = loadClass(itfs[i].replace('/', '.')).getMethods();
128       for (int j = 0; j < meths.length; ++j) {
129         Method JavaDoc meth = meths[j];
130         String JavaDoc name = meth.getName();
131         String JavaDoc desc = Type.getMethodDescriptor(meth);
132
133         if (methods.contains(name + desc)) {
134           continue;
135         }
136         methods.add(name + desc);
137
138         CodeVisitor cv = cw.visitMethod(ACC_PUBLIC, name, desc, null, null);
139
140         if (name.startsWith("get")) {
141           String JavaDoc field = getFieldName(name, 3);
142
143           if (!desc.endsWith(")Ljava/lang/String;")) {
144             boolean single = desc.indexOf(")[") == -1;
145             // generates code in "astGetNodes()"
146
agn.visitInsn(DUP);
147             agn.visitIntInsn(SIPUSH, count++);
148             agn.visitLdcInsn(getASTName(name, single));
149             agn.visitInsn(AASTORE);
150
151             // generates code in "astGetNodes(String)"
152
if (single) {
153               generateGetNodeMethod(agns, owner, name, field, desc.substring(2), agnsEnd);
154             } else {
155               generateGetNodesMethod(agns, owner, name, field, agnsEnd);
156             }
157           }
158
159           if (desc.startsWith("()[")) {
160             // case of a getter method for a sub node with arity * or +
161
String JavaDoc fieldDesc = "Ljava/util/List;";
162             String JavaDoc elemDesc = desc.substring(3);
163
164             // generates the field
165
cw.visitField(ACC_PRIVATE, field, fieldDesc, null, null);
166
167             // generates the getter method
168
cv.visitVarInsn(ALOAD, 0);
169             cv.visitFieldInsn(GETFIELD, owner, field, fieldDesc);
170             cv.visitVarInsn(ALOAD, 0);
171             cv.visitFieldInsn(GETFIELD, owner, field, fieldDesc);
172             cv.visitMethodInsn(
173               INVOKEINTERFACE, "java/util/List", "size", "()I");
174             cv.visitTypeInsn(
175               ANEWARRAY, elemDesc.substring(1, elemDesc.length() - 1));
176             cv.visitMethodInsn(
177               INVOKEINTERFACE,
178               "java/util/List",
179               "toArray",
180             "([Ljava/lang/Object;)[Ljava/lang/Object;");
181             cv.visitTypeInsn(CHECKCAST, "[" + elemDesc);
182             cv.visitInsn(ARETURN);
183             cv.visitMaxs(0, 0);
184
185             // generates code to initialize the field in the constructor
186
icv.visitVarInsn(ALOAD, 0);
187             icv.visitTypeInsn(NEW, "java/util/ArrayList");
188             icv.visitInsn(DUP);
189             icv.visitMethodInsn(
190               INVOKESPECIAL, "java/util/ArrayList", "<init>", "()V");
191             icv.visitFieldInsn(PUTFIELD, owner, field, fieldDesc);
192
193             generateAddNodesMethod(
194               aan, owner, name, field, fieldDesc, aanEnd, true);
195             generateAddNodesMethod(
196               arn, owner, name, field, fieldDesc, arnEnd, false);
197           } else {
198             // case of a getter method for a sub node with arity 1 or ?
199
String JavaDoc fieldDesc = desc.substring(2);
200
201             // generates the field
202
cw.visitField(ACC_PRIVATE, field, fieldDesc, null, null);
203
204             // generates the getter method
205
cv.visitVarInsn(ALOAD, 0);
206             cv.visitFieldInsn(GETFIELD, owner, field, fieldDesc);
207             cv.visitInsn(ARETURN);
208             cv.visitMaxs(0, 0);
209
210             if (fieldDesc.equals("Ljava/lang/String;")) {
211               // case of an attribute:
212

213               // generates code in "astGetAttributes"
214
aga.visitVarInsn(ALOAD, 1);
215               aga.visitLdcInsn(getASTName(name, true));
216               aga.visitVarInsn(ALOAD, 0);
217               aga.visitFieldInsn(GETFIELD, owner, field, fieldDesc);
218               aga.visitMethodInsn(
219                 INVOKEVIRTUAL,
220                 "java/util/HashMap",
221                 "put",
222               "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
223               aga.visitInsn(POP);
224
225               // generates code in "astSetAttributes"
226
asa.visitVarInsn(ALOAD, 0);
227               asa.visitVarInsn(ALOAD, 1);
228               asa.visitLdcInsn(getASTName(name, true));
229               asa.visitMethodInsn(
230                 INVOKEINTERFACE,
231                 "java/util/Map",
232                 "get",
233               "(Ljava/lang/Object;)Ljava/lang/Object;");
234               asa.visitTypeInsn(CHECKCAST, "java/lang/String");
235               asa.visitFieldInsn(PUTFIELD, owner, field, fieldDesc);
236             } else {
237               // case of a sub node:
238
generateAddNodeMethod(
239                 aan, owner, name, field, fieldDesc, aanEnd, true);
240               generateAddNodeMethod(
241                 arn, owner, name, field, fieldDesc, arnEnd, false);
242             }
243           }
244         } else if (name.startsWith("set")) {
245           String JavaDoc field = getFieldName(name, 3);
246           String JavaDoc fieldDesc = desc.substring(1, desc.length() - 2);
247           cv.visitVarInsn(ALOAD, 0);
248           cv.visitVarInsn(ALOAD, 1);
249           cv.visitFieldInsn(PUTFIELD, owner, field, fieldDesc);
250           cv.visitInsn(RETURN);
251           cv.visitMaxs(0, 0);
252         } else if (name.startsWith("add")) {
253           String JavaDoc field = getFieldName(name, 3) + "s";
254           String JavaDoc fieldDesc = "Ljava/util/List;";
255           cv.visitVarInsn(ALOAD, 0);
256           cv.visitFieldInsn(GETFIELD, owner, field, fieldDesc);
257           cv.visitVarInsn(ALOAD, 1);
258           cv.visitMethodInsn(
259             INVOKEINTERFACE, "java/util/List", "add", "(Ljava/lang/Object;)Z");
260           cv.visitInsn(POP);
261           cv.visitInsn(RETURN);
262           cv.visitMaxs(0, 0);
263         } else if (name.startsWith("remove")) {
264           String JavaDoc field = getFieldName(name, 6) + "s";
265           String JavaDoc fieldDesc = "Ljava/util/List;";
266           cv.visitVarInsn(ALOAD, 0);
267           cv.visitFieldInsn(GETFIELD, owner, field, fieldDesc);
268           cv.visitVarInsn(ALOAD, 1);
269           cv.visitMethodInsn(
270             INVOKEINTERFACE, "java/util/List", "remove", "(Ljava/lang/Object;)Z");
271           cv.visitInsn(POP);
272           cv.visitInsn(RETURN);
273           cv.visitMaxs(0, 0);
274         }
275       }
276     }
277
278     icv.visitInsn(RETURN);
279     icv.visitMaxs(0, 0);
280
281     aga.visitVarInsn(ALOAD, 1);
282     aga.visitInsn(ARETURN);
283     aga.visitMaxs(0, 0);
284
285     asa.visitInsn(RETURN);
286     asa.visitMaxs(0, 0);
287
288     agn.visitInsn(ARETURN);
289     agn.visitMaxs(0, 0);
290
291     agns.visitLabel(agnsEnd);
292     agns.visitVarInsn(ALOAD, 2);
293     agns.visitInsn(ARETURN);
294     agns.visitMaxs(0, 0);
295
296     aan.visitLabel(aanEnd);
297     aan.visitInsn(RETURN);
298     aan.visitMaxs(0, 0);
299
300     arn.visitLabel(arnEnd);
301     arn.visitInsn(RETURN);
302     arn.visitMaxs(0, 0);
303
304     return cw;
305   }
306   
307   protected Class JavaDoc defineClass (final String JavaDoc name, final byte[] b) {
308     bytecodes.put(name.replace('.', '/') + ".class", b);
309     return defineClass(name, b, 0, b.length);
310   }
311
312   public InputStream JavaDoc getResourceAsStream (final String JavaDoc name) {
313     InputStream JavaDoc is = super.getResourceAsStream(name);
314     if (is == null) {
315       byte[] b = (byte[])bytecodes.get(name);
316       if (b != null) {
317         is = new ByteArrayInputStream JavaDoc(b);
318       }
319     }
320     return is;
321   }
322   
323   private int getNodeCount (final String JavaDoc[] itfs) throws ClassNotFoundException JavaDoc {
324     int count = 0;
325     Set JavaDoc methods = new HashSet JavaDoc();
326     for (int i = 0; i < itfs.length; ++i) {
327       Method JavaDoc[] meths = loadClass(itfs[i].replace('/', '.')).getMethods();
328       for (int j = 0; j < meths.length; ++j) {
329         Method JavaDoc meth = meths[j];
330         String JavaDoc name = meth.getName();
331         String JavaDoc desc = Type.getMethodDescriptor(meth);
332         if (methods.contains(name + desc)) {
333           continue;
334         }
335         methods.add(name + desc);
336         if (name.startsWith("get") && !desc.endsWith(")Ljava/lang/String;")) {
337           ++count;
338         }
339       }
340     }
341     return count;
342   }
343
344   private void generateGetNodeMethod (
345     final CodeVisitor cv,
346     final String JavaDoc owner, final String JavaDoc name,
347     final String JavaDoc field, final String JavaDoc fieldDesc, final Label end)
348   {
349     Label l = generateIf(cv, 1, getASTName(name, true));
350     cv.visitInsn(ICONST_1);
351     cv.visitTypeInsn(ANEWARRAY, Type.getInternalName(Node.class));
352     cv.visitInsn(DUP);
353     cv.visitInsn(ICONST_0);
354     cv.visitVarInsn(ALOAD, 0);
355     cv.visitFieldInsn(GETFIELD, owner, field, fieldDesc);
356     cv.visitInsn(AASTORE);
357     cv.visitVarInsn(ASTORE, 2);
358     cv.visitJumpInsn(GOTO, end);
359     cv.visitLabel(l);
360   }
361
362   private void generateGetNodesMethod (
363     final CodeVisitor cv,
364     final String JavaDoc owner, final String JavaDoc name,
365     final String JavaDoc field, final Label end)
366   {
367     Label l = generateIf(cv, 1, getASTName(name, false));
368     cv.visitVarInsn(ALOAD, 0);
369     cv.visitFieldInsn(GETFIELD, owner, field, "Ljava/util/List;");
370     cv.visitVarInsn(ALOAD, 0);
371     cv.visitFieldInsn(GETFIELD, owner, field, "Ljava/util/List;");
372     cv.visitMethodInsn(
373       INVOKEINTERFACE, "java/util/List", "size", "()I");
374     cv.visitTypeInsn(
375       ANEWARRAY, Type.getInternalName(Node.class));
376     cv.visitMethodInsn(
377       INVOKEINTERFACE,
378       "java/util/List",
379       "toArray",
380     "([Ljava/lang/Object;)[Ljava/lang/Object;");
381     cv.visitTypeInsn(CHECKCAST, "[" + Type.getDescriptor(Node.class));
382     cv.visitVarInsn(ASTORE, 2);
383     cv.visitJumpInsn(GOTO, end);
384     cv.visitLabel(l);
385   }
386
387   private void generateAddNodeMethod (
388     final CodeVisitor cv,
389     final String JavaDoc owner, final String JavaDoc name,
390     final String JavaDoc field, final String JavaDoc fieldDesc,
391     final Label end, final boolean add)
392   {
393     String JavaDoc s = getASTName(name, true);
394     Label l = generateIf(cv, 2, s);
395     cv.visitVarInsn(ALOAD, 0);
396     if (add) {
397       cv.visitVarInsn(ALOAD, 1);
398       cv.visitTypeInsn(
399         CHECKCAST, fieldDesc.substring(1, fieldDesc.length() - 1));
400     } else {
401       cv.visitInsn(ACONST_NULL);
402     }
403     cv.visitFieldInsn(PUTFIELD, owner, field, fieldDesc);
404     cv.visitJumpInsn(GOTO, end);
405     cv.visitLabel(l);
406   }
407
408   private void generateAddNodesMethod (
409     final CodeVisitor cv,
410     final String JavaDoc owner, final String JavaDoc name,
411     final String JavaDoc field, final String JavaDoc fieldDesc,
412     final Label end, final boolean add)
413   {
414     String JavaDoc s = getASTName(name, false);
415     Label l = generateIf(cv, 2, s);
416     cv.visitVarInsn(ALOAD, 0);
417     cv.visitFieldInsn(GETFIELD, owner, field, fieldDesc);
418     cv.visitVarInsn(ALOAD, 1);
419     cv.visitMethodInsn(
420       INVOKEINTERFACE,
421       "java/util/List",
422       add ? "add" : "remove",
423       add ? "(Ljava/lang/Object;)Z" : "(Ljava/lang/Object;)Z");
424     cv.visitInsn(POP);
425     cv.visitJumpInsn(GOTO, end);
426     cv.visitLabel(l);
427   }
428   
429   private Label generateIf (final CodeVisitor cv, final int var, final String JavaDoc name) {
430     Label l = new Label();
431     cv.visitVarInsn(ALOAD, var);
432     cv.visitLdcInsn(name);
433     cv.visitMethodInsn(
434       INVOKEVIRTUAL,
435       "java/lang/Object",
436       "equals",
437     "(Ljava/lang/Object;)Z");
438     cv.visitJumpInsn(IFEQ, l);
439     return l;
440   }
441   
442   public static String JavaDoc getASTName (final String JavaDoc name, final boolean single) {
443     char c = Character.toLowerCase(name.charAt(3));
444     if (single) {
445       return c + name.substring(4);
446     } else {
447       return c + name.substring(4, name.length() - 1);
448     }
449   }
450
451   public static String JavaDoc getFieldName (final String JavaDoc name, final int prefix) {
452     char c = Character.toLowerCase(name.charAt(prefix));
453     return "_" + c + name.substring(prefix + 1);
454   }
455 }
456
Popular Tags