KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > fractal > julia > asm > InterfaceClassGenerator


1 /***
2  * Julia: France Telecom's implementation of the Fractal API
3  * Copyright (C) 2001-2002 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.julia.asm;
25
26 import org.objectweb.fractal.julia.loader.Initializable;
27 import org.objectweb.fractal.julia.loader.Tree;
28
29 import org.objectweb.asm.CodeVisitor;
30 import org.objectweb.asm.Label;
31 import org.objectweb.asm.Type;
32
33 import java.lang.reflect.Method JavaDoc;
34 import java.util.ArrayList JavaDoc;
35 import java.util.Arrays JavaDoc;
36
37 /**
38  * A class generator to generate {@link org.objectweb.fractal.api.Interface}
39  * classes. This class generator generates sub classes of a given
40  * {@link org.objectweb.fractal.api.Interface} class that
41  * implements the given set of interfaces. The super class must be a sub class
42  * of the {@link org.objectweb.fractal.julia.BasicComponentInterface} class.
43  * <p>
44  * The code generated for the I interface below is the following:
45  * <pre>
46  * public interface I {
47  * void m ();
48  * }
49  *
50  * public class <i>XYZ</i> extends <i>superClass</i> implements I, Generated {
51  *
52  * private I impl;
53  *
54  * public <i>XYZ</i> () {
55  * }
56  *
57  * public <i>XYZ</i> (Component o, String n, Type t, boolean b, Object impl) {
58  * super(o, n, t, b, impl);
59  * }
60  *
61  * public void m () {
62  * impl.m();
63  * }
64  *
65  * public Object getFcItfImpl () {
66  * return impl;
67  * }
68  *
69  * public void setFcItfImpl (Object impl) {
70  * this.impl = (I)impl;
71  * }
72  *
73  * public String getFcGeneratorParameters () {
74  * return "(... <i>superClass</i> (I))";
75  * }
76  * }
77  * </pre>
78  * If there is more than one interface, some additional casts are used:
79  * <pre>
80  * public class <i>XY</i> extends <i>superClass</i> implements I, J, Generated {
81  *
82  * private Object impl;
83  *
84  * public <i>XY</i> () {
85  * }
86  *
87  * public <i>XY</i> (Component o, String n, Type t, boolean b, Object impl) {
88  * super(o, n, t, b, impl);
89  * }
90  *
91  * public void m () {
92  * ((I)impl).m();
93  * }
94  *
95  * public void n () {
96  * ((J)impl).n();
97  * }
98  *
99  * public Object getFcItfImpl () {
100  * return impl;
101  * }
102  *
103  * public void setFcItfImpl (Object impl) {
104  * this.impl = impl;
105  * }
106  *
107  * public String getFcGeneratorParameters () {
108  * return "(... <i>superClass</i> (I J))";
109  * }
110  * }
111  * </pre>
112  */

113
114 public class InterfaceClassGenerator extends AbstractClassGenerator
115   implements Initializable
116 {
117
118   /**
119    * The 'impl' field descriptor.
120    */

121
122   private String JavaDoc implFieldDesc;
123
124   /**
125    * Initializes this object with the given arguments. These arguments must be
126    * of the form "(superClassName)", where superClassName is the name of the
127    * super class to be used for the class generated by this class generator.
128    *
129    * @param args the arguments to be used to initialize this object. The format
130    * of these arguments depends on the class of this object.
131    * @throws Exception if a problem occurs during the object initialization.
132    */

133
134   public void initialize (final Tree args) throws Exception JavaDoc {
135     this.superClass = args.getSubTree(0).toString().replace('.', '/');
136   }
137
138   /**
139    * Initializes this class generator with the given arguments. This method
140    * requires arguments of the form "(objectDescriptor (itfName1 ...
141    * itfNameN))", where itfName1 ... itfNameN are the names of the interfaces it
142    * must implement.
143    *
144    * @param args the descriptor of the class to be generated.
145    */

146
147   protected void parseArgs (final Tree args) {
148     interfaces = new ArrayList JavaDoc(Arrays.asList(args.getSubTree(1).getSubTrees()));
149     for (int i = 0; i < interfaces.size(); ++i) {
150       interfaces.set(i, interfaces.get(i).toString().replace('.', '/'));
151     }
152   }
153
154   /**
155    * Returns the source of the class to be generated. This method returns
156    * "INTERFACE[...]", where "..." is the name of the interface implemented by
157    * the generated class.
158    *
159    * @return the source of the class to be generated.
160    */

161
162   protected String JavaDoc getSource () {
163     String JavaDoc s = interfaces.get(0).toString();
164     if (s.lastIndexOf('/') != -1) {
165       s = s.substring(s.lastIndexOf('/') + 1);
166     }
167     return "INTERFACE[" + s + "]";
168   }
169
170   /**
171    * Generates the constructor of the class to be generated. This method
172    * generates a default constructor and a constructor similar to the
173    * constructor of the {@link
174    * org.objectweb.fractal.julia.BasicComponentInterface} class.
175    *
176    * @throws ClassGenerationException if a problem occurs.
177    */

178
179   protected void generateConstructor () throws ClassGenerationException {
180     // default constructor needed for reflective instantiation in BasicLoader
181
CodeVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
182     mv.visitVarInsn(ALOAD, 0);
183     mv.visitMethodInsn(INVOKESPECIAL, superClass, "<init>", "()V");
184     mv.visitInsn(RETURN);
185     mv.visitMaxs(1, 1);
186
187     // constructor of the BasicComponentInterface class
188
mv = cw.visitMethod(
189       ACC_PUBLIC,
190       "<init>",
191       "(Lorg/objectweb/fractal/api/Component;" +
192       "Ljava/lang/String;" +
193       "Lorg/objectweb/fractal/api/Type;" +
194       "ZLjava/lang/Object;)V",
195       null,
196       null);
197     mv.visitVarInsn(ALOAD, 0);
198     mv.visitVarInsn(ALOAD, 1);
199     mv.visitVarInsn(ALOAD, 2);
200     mv.visitVarInsn(ALOAD, 3);
201     mv.visitVarInsn(ILOAD, 4);
202     mv.visitVarInsn(ALOAD, 5);
203     mv.visitMethodInsn(
204       INVOKESPECIAL,
205       superClass,
206       "<init>",
207       "(Lorg/objectweb/fractal/api/Component;" +
208       "Ljava/lang/String;" +
209       "Lorg/objectweb/fractal/api/Type;" +
210       "ZLjava/lang/Object;)V");
211     mv.visitInsn(RETURN);
212     mv.visitMaxs(6, 6);
213   }
214
215   /**
216    * Calls the overriden method and generates the {@link
217    * org.objectweb.fractal.julia.ComponentInterface#getFcItfImpl getFcItfImpl}
218    * and {@link org.objectweb.fractal.julia.ComponentInterface#setFcItfImpl
219    * setFcItfImpl} methods.
220    *
221    * @throws ClassGenerationException if a problem occurs.
222    */

223
224   protected void generateDefaultMethods () throws ClassGenerationException {
225     super.generateDefaultMethods();
226     // adds the 'impl' field. its type depends on the number of interfaces
227
if (interfaces.size() == 1) {
228       implFieldDesc = "L" + (String JavaDoc)interfaces.get(0) + ";";
229     } else {
230       implFieldDesc = "Ljava/lang/Object;";
231     }
232     cw.visitField(ACC_PRIVATE, "impl", implFieldDesc, null, null);
233     // generates the getFcItfImpl method
234
String JavaDoc mName = "getFcItfImpl";
235     String JavaDoc mDesc = "()Ljava/lang/Object;";
236     CodeVisitor mv = cw.visitMethod(ACC_PUBLIC, mName, mDesc, null, null);
237     mv.visitVarInsn(ALOAD, 0);
238     mv.visitFieldInsn(GETFIELD, name, "impl", implFieldDesc);
239     mv.visitInsn(ARETURN);
240     mv.visitMaxs(1, 1);
241     // generates the setFcItfImpl method
242
mName = "setFcItfImpl";
243     mDesc = "(Ljava/lang/Object;)V";
244     mv = cw.visitMethod(ACC_PUBLIC, mName, mDesc, null, null);
245     mv.visitVarInsn(ALOAD, 0);
246     mv.visitVarInsn(ALOAD, 1);
247     if (interfaces.size() == 1) {
248       // adds a cast if there is only one interface
249
mv.visitTypeInsn(CHECKCAST, (String JavaDoc)interfaces.get(0));
250     }
251     mv.visitFieldInsn(PUTFIELD, name, "impl", implFieldDesc);
252     mv.visitInsn(RETURN);
253     mv.visitMaxs(2, 2);
254   }
255
256   /**
257    * Generates a method that forwards calls to the 'impl' object.
258    *
259    * @param m the method that must be generated.
260    */

261
262   protected void generateMethod (final Method JavaDoc m) {
263     // generates the header of the forwarder method
264
String JavaDoc name = m.getName();
265     String JavaDoc itf = Type.getInternalName(m.getDeclaringClass());
266     String JavaDoc mDesc = Type.getMethodDescriptor(m);
267     Class JavaDoc[] exceptions = m.getExceptionTypes();
268     String JavaDoc[] excepts = new String JavaDoc[exceptions.length];
269     for (int i = 0; i < exceptions.length; ++i) {
270       excepts[i] = Type.getInternalName(exceptions[i]);
271     }
272     if (name.equals("hashCode") && m.getParameterTypes().length == 0) {
273       // "hashCode" already defined in super class
274
return;
275     }
276     if (name.equals("equals")) {
277       Class JavaDoc[] args = m.getParameterTypes();
278       if (args.length == 1 && args[0].equals(Object JavaDoc.class)) {
279         // "equals" already defined in super class
280
return;
281       }
282     }
283     CodeVisitor mv = cw.visitMethod(ACC_PUBLIC, name, mDesc, excepts, null);
284     // step 1 : load the 'impl' field
285
mv.visitVarInsn(ALOAD, 0);
286     mv.visitFieldInsn(GETFIELD, this.name, "impl", implFieldDesc);
287     // checks that 'impl' is not null
288
Label l = new Label();
289     mv.visitInsn(DUP);
290     mv.visitJumpInsn(IFNONNULL, l);
291     mv.visitTypeInsn(NEW, "java/lang/NullPointerException");
292     mv.visitInsn(DUP);
293     mv.visitLdcInsn(
294       "Trying to invoke a method on a client interface, " +
295       "or on a server interface whose complementary interface is not bound.");
296     mv.visitMethodInsn(
297       INVOKESPECIAL,
298       "java/lang/NullPointerException", "<init>", "(Ljava/lang/String;)V");
299     mv.visitInsn(ATHROW);
300     mv.visitLabel(l);
301     // adds a cast if there is more than one interface
302
if (interfaces.size() > 1) {
303       mv.visitTypeInsn(CHECKCAST, itf);
304     }
305     // step 2 : push parameters p0,...
306
Class JavaDoc[] params = m.getParameterTypes();
307     int offset = 1;
308     for (int i = 0; i < params.length; ++i) {
309       mv.visitVarInsn(ILOAD + getOpcodeOffset(params[i]), offset);
310       offset += getSize(params[i]);
311     }
312     // step 3 : invoke method m
313
mv.visitMethodInsn(INVOKEINTERFACE, itf, name, mDesc);
314     // step 4 : return the result
315
Class JavaDoc result = m.getReturnType();
316     if (result == Void.TYPE) {
317       mv.visitInsn(RETURN);
318     } else {
319       mv.visitInsn(IRETURN + getOpcodeOffset(result));
320     }
321     // sets the maximum stack size and the maximum number of local variables
322
int maxStack = Math.max(4, Math.max(offset, getSize(result)));
323     int maxLocals = Math.max(offset, getSize(result));
324     mv.visitMaxs(maxStack, maxLocals);
325   }
326 }
327
Popular Tags