Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/chaoswg/xtc4y/AbstractClassImplementor.java


1   //$Header: /cvsroot/xtc4y/xtc4y/src/com/chaoswg/xtc4y/AbstractClassImplementor.java,v 1.1.1.1 2003/08/07 13:40:26 toggm Exp $
2   /******************************************************************************
3    * XTC4y - eXtreme Testing Collection 4 you                                   *
4    * -------------------------------------------------------------------------- *
5    * URL: http://www.chaoswg.com/xtc4y                                          *
6    * Author: Mike Toggweiler (2.dog@gmx.ch)                                     *
7    *                                                                            *
8    * Last Updated: $Date: 2003/08/07 13:40:26 $, by $Author: toggm $            *
9    * Version: $Revision: 1.1.1.1 $                                                  *
10   * -------------------------------------------------------------------------- *
11   * COPYRIGHT:   (c) 2003 by Mike Toggweiler                                   *
12   *                                                                            *
13   * This program is free software; you can redistribute it and/or modify       *
14   * it under the terms of the GNU General Public License as published by       *
15   * the Free Software Foundation; either version 2 of the License, or          *
16   * (at your option) any later version.                                        *
17   *****************************************************************************/
18  package com.chaoswg.xtc4y;
19  
20  import java.io.ByteArrayInputStream;
21  import java.io.ByteArrayOutputStream;
22  import java.io.DataInputStream;
23  import java.io.DataOutputStream;
24  import java.io.FileOutputStream;
25  import java.io.InputStream;
26  import java.io.IOException;
27  
28  import java.lang.reflect.Method;
29  import java.lang.reflect.Modifier;
30  import java.lang.reflect.Constructor;
31  
32  import java.util.Vector;
33  
34  import com.chaoswg.util.ExceptionPrinter;
35  
36  import com.chaoswg.xtc4y.classloaders.ByteArrayClassLoader;
37  import com.chaoswg.xtc4y.classdesc.AttributeInfo;
38  import com.chaoswg.xtc4y.classdesc.Attribute;
39  import com.chaoswg.xtc4y.classdesc.SourceFileAttribute;
40  import com.chaoswg.xtc4y.classdesc.BaseType;
41  import com.chaoswg.xtc4y.classdesc.ClassCPEntry;
42  import com.chaoswg.xtc4y.classdesc.ClassDescriptor;
43  import com.chaoswg.xtc4y.classdesc.ClassAccessFlags;
44  import com.chaoswg.xtc4y.classdesc.CodeAttribute;
45  import com.chaoswg.xtc4y.classdesc.MethodAccessFlags;
46  import com.chaoswg.xtc4y.classdesc.MethodInfo;
47  import com.chaoswg.xtc4y.classdesc.NameAndTypeCPEntry;
48  import com.chaoswg.xtc4y.classdesc.MethodrefCPEntry;
49  import com.chaoswg.xtc4y.classdesc.code.Code;
50  import com.chaoswg.xtc4y.classdesc.code.instructions.UnaryInstruction;
51  import com.chaoswg.xtc4y.classdesc.code.instructions.Instruction;
52  import com.chaoswg.xtc4y.classdesc.code.instructions.InvokeSpecial;
53  
54  /**
55   * This class is used to implement an abstract class for testing purposes.
56   * It creates a subclass of it which implements all abstract methods
57   * @author Mike Toggweiler
58   **/
59  public class AbstractClassImplementor {
60      
61      private boolean writeGeneratedFile = false;
62      private ByteArrayClassLoader loader = new ByteArrayClassLoader();
63      
64      /**
65       * Construct a new AbstractClassLoad
66       **/
67      public AbstractClassImplementor() {
68      }
69  
70      /**
71       * Construct a new AbstractClassImplementor 
72       * @param writeOutput true if generated output file should be written in 
73       * a class file
74       **/
75      public AbstractClassImplementor(boolean writeOutput) {
76    writeGeneratedFile = writeOutput;
77      }       
78  
79      /**
80       * Get an implementation of the abstract class referenced by the name
81       * @param name the name of the class
82       * @return a class if found
83       * @exception ClassNotFoundException
84       **/
85      public Class getImplementedClass(String name) 
86    throws ClassNotFoundException {
87    return getImplementedClass(Class.forName(name));
88      }
89  
90      /**
91       * Get an implementation of the abstract class referenced by the class 
92       * object
93       * @param orig the original class to implement
94       * @return a class if found
95       * @exception ClassNotFoundException
96       **/
97      public Class getImplementedClass(Class orig) 
98    throws ClassNotFoundException {    
99    try {
100       if (orig.isInterface()) {
101     //TBD, implement support for interfaces
102     //return getImplementedIfcClass(orig);
103     return null;
104       }
105       
106       int mod = orig.getModifiers();  
107       if (!Modifier.isAbstract(mod)) {
108     return orig;
109       }
110       
111       
112       
113       ClassDescriptor descriptor = new ClassDescriptor();      
114       
115       ClassAccessFlags classAccess = new ClassAccessFlags((short)0);     
116       classAccess.setIsPublic(Modifier.isPublic(mod));
117       classAccess.setIsAbstract(false);
118       descriptor.setClassAccess(classAccess);
119       
120       //set class structure
121       String name = orig.getName();
122       name = name.replace('.','/');
123       ClassCPEntry superCl = new ClassCPEntry(name);
124       descriptor.setSuperClass(superCl);      
125       name += "_impl";
126       descriptor.setThisClass(new ClassCPEntry(name));      
127       
128       //implement all abstract methods
129       Method[] methods = orig.getMethods();
130       int mmod;
131       for (int i=0; i<methods.length; ++i) {
132     mmod = methods[i].getModifiers();
133     if (Modifier.isAbstract(mmod)) {
134         MethodInfo meth = getMethodImplementation(methods[i]);
135         System.out.println("Add method:"+meth);
136         descriptor.addMethod(meth); 
137     }
138       }
139       
140       //add all declared constructors
141       Constructor[] constr = orig.getDeclaredConstructors();
142       for (int i=0; i<constr.length; ++i) {
143     MethodInfo cons = getConstructorImplementation(constr[i], 
144                      superCl);
145     if (cons != null) {
146         System.out.println("Add constructor:"+cons);
147         //null if constructor was private
148         descriptor.addMethod(cons);
149     }
150       }
151             
152       //print new class into byte array
153       ByteArrayOutputStream baos = new ByteArrayOutputStream();
154       DataOutputStream dos = new DataOutputStream(baos);      
155       
156       //write new class
157       descriptor.writeClass(dos);
158       
159       byte[] bytes = baos.toByteArray();
160       
161       if (writeGeneratedFile) {
162     writeClassFile(bytes, name);
163       }
164 
165       dos.close();            
166       baos.close();   
167       
168       System.out.println("Define class:"+name);
169       return loader.defineClass1(name, bytes, 0, bytes.length);
170   }
171   catch (IOException ioe) {
172       System.out.println("Couldn't load class data:"+
173              ExceptionPrinter.getStackTrace(ioe));
174   }
175   throw new ClassNotFoundException();
176     }
177 
178     /**
179      * @return a descriptor concatenated of an array of classes and the 
180      * return type
181      **/
182     private String getDescriptor(Class[] params, Class ret) {
183   String desc = "(";  
184   for (int i=0; i<params.length; ++i) {
185       desc += getBaseType(params[i]);        
186   }
187   
188   desc += ")";
189   //add return type
190   if (ret != null) {
191       desc += getBaseType(ret);
192   }
193 
194   return desc;
195     }
196     
197     /**
198      * @return the string representation of the basetype of a given class
199      **/
200     private String getBaseType(Class cl) {
201   System.out.println("Check class:"+cl+":"+cl.isPrimitive());
202   if (cl.isPrimitive()) {
203       if (Integer.TYPE.isAssignableFrom(cl)) {
204     return BaseType.INT;
205       }
206       else if (Short.TYPE.isAssignableFrom(cl)) {
207     return BaseType.SHORT;
208       }
209       else if (Byte.TYPE.isAssignableFrom(cl)) {
210     return BaseType.BYTE;
211       }
212       else if (Character.TYPE.isAssignableFrom(cl)) {
213     return BaseType.CHAR;
214       }
215       else if (Long.TYPE.isAssignableFrom(cl)) {
216     return BaseType.LONG;
217       }
218       else if (Float.TYPE.isAssignableFrom(cl)) {
219     return BaseType.FLOAT;
220       }
221       else if (Double.TYPE.isAssignableFrom(cl)) {
222     return BaseType.DOUBLE;
223       }
224       else if (Boolean.TYPE.isAssignableFrom(cl)) {
225     return BaseType.BOOLEAN;
226       }      
227       else if (Void.TYPE.isAssignableFrom(cl)) {
228     return BaseType.VOID;
229       }
230       return null;
231   }
232   else if (cl.isArray()) {
233       return cl.getName();
234   }  
235   System.out.println("Class is wheter an array nor primitive:"+cl);
236   //in all other cases assuem that the class is an object
237   String name = cl.getName();
238   name = name.replace('.', '/');
239   return BaseType.REFERENCE + name + ";";
240     }
241 
242     /**
243      * @return a constructor implementation with a call to the super 
244      * constructor
245      **/
246     private MethodInfo getConstructorImplementation(Constructor cons, 
247                 ClassCPEntry superCl) {
248   int mod = cons.getModifiers();
249   MethodAccessFlags access = new MethodAccessFlags((short)0);
250   if (Modifier.isPrivate(mod)) {
251       return null;
252   }
253   else if (Modifier.isPublic(mod)) {
254       access.setPublic();
255   }
256   else if (Modifier.isProtected(mod)) {
257       access.setProtected();
258   }
259   access.setIsSynchronized(Modifier.isSynchronized(mod));
260   //TBD: check if other flags are allowed on a constructor
261 
262   String desc = getDescriptor(cons.getParameterTypes(), Void.TYPE);
263   
264   MethodInfo consImpl = new MethodInfo(access, 
265                MethodInfo.CONSTRUCTOR_NAME, 
266                desc);
267   
268   //add code implementation which calls super constructor
269   Code code = new Code();
270   Class[] params = cons.getParameterTypes();
271   int index = 0;
272   //load instructions
273   code.addInstruction(getLoadInstruction(Object.class, index++));
274   for (int i=0; i<params.length; ++i) {
275       code.addInstruction(getLoadInstruction(params[i], index++));
276   }
277   //invokespecial instruction
278   NameAndTypeCPEntry nat = 
279       new NameAndTypeCPEntry(MethodInfo.CONSTRUCTOR_NAME, desc);
280              
281   MethodrefCPEntry methodr = new MethodrefCPEntry(superCl, nat);
282   code.addInstruction(new InvokeSpecial(methodr));
283   //add a return depending on the return type      
284   code.addInstruction(getReturnInstruction(Void.TYPE));
285      
286   consImpl.addAttribute(new AttributeInfo(new CodeAttribute(code)));
287 
288   //add exception attributes
289   
290   return consImpl;
291     }
292 
293     /**
294      * @return a load instruction dependant on the basetype
295      **/
296     private Instruction getLoadInstruction(Class type, int index) {
297   if (!type.isPrimitive() && !type.isArray()) {
298       return new UnaryInstruction((byte)
299           (UnaryInstruction.ALOAD_0+index));
300   }
301   else if (type.isArray()) {
302       return getArrayLoadInstruction(type);
303   }
304   else if (Double.TYPE.isAssignableFrom(type)) {
305       return new UnaryInstruction((byte)
306           (UnaryInstruction.DLOAD_0+index));
307   }
308   else if (Float.TYPE.isAssignableFrom(type)) {
309       return new UnaryInstruction((byte)
310           (UnaryInstruction.FLOAD_0+index));
311   }
312   else if (Long.TYPE.isAssignableFrom(type)) {
313       return new UnaryInstruction((byte)
314           (UnaryInstruction.LLOAD_0+index));
315   }
316   else {
317       return new UnaryInstruction((byte)
318           (UnaryInstruction.ILOAD_0+index));
319   }
320     }
321 
322     /**
323      * @return a load instruction dependant on the basetype array
324      **/
325     private Instruction getArrayLoadInstruction(Class type) {
326   if (!type.isPrimitive()) {
327       return new UnaryInstruction(UnaryInstruction.AALOAD);
328   }
329   else if (Double.TYPE.isAssignableFrom(type)) {
330       return new UnaryInstruction(UnaryInstruction.DALOAD);
331   }
332   else if (Float.TYPE.isAssignableFrom(type)) {
333       return new UnaryInstruction(UnaryInstruction.FALOAD);
334   }
335   else if (Long.TYPE.isAssignableFrom(type)) {
336       return new UnaryInstruction(UnaryInstruction.LALOAD);
337   }
338   else if (Integer.TYPE.isAssignableFrom(type)) {
339       return new UnaryInstruction(UnaryInstruction.IALOAD);
340   }
341   else if (Short.TYPE.isAssignableFrom(type)) {
342       return new UnaryInstruction(UnaryInstruction.SALOAD);
343   }
344   else if (Byte.TYPE.isAssignableFrom(type)) {
345       return new UnaryInstruction(UnaryInstruction.BALOAD);
346   }
347   else if (Character.TYPE.isAssignableFrom(type)) {
348       return new UnaryInstruction(UnaryInstruction.CALOAD);
349   }
350   else if (Boolean.TYPE.isAssignableFrom(type)) {
351       return new UnaryInstruction(UnaryInstruction.IALOAD);
352   }
353   else {
354       throw new ClassFormatError("Array Descriptor type unknown:"+type);
355   }
356     }
357 
358     /**
359      * @return a return instruction depending on the return type
360      **/
361     private Instruction getReturnInstruction(Class ret) {
362   if (ret.isArray() || !ret.isPrimitive()) {
363       return new UnaryInstruction(UnaryInstruction.ARETURN);
364   }
365   else if (Void.TYPE.isAssignableFrom(ret)) {
366       return new UnaryInstruction(UnaryInstruction.RETURN);
367   }
368   else if (Double.TYPE.isAssignableFrom(ret)) {
369       return new UnaryInstruction(UnaryInstruction.DRETURN);
370   }
371   else if (Float.TYPE.isAssignableFrom(ret)) {
372       return new UnaryInstruction(UnaryInstruction.FRETURN);
373   }
374   else if (Long.TYPE.isAssignableFrom(ret)) {
375       return new UnaryInstruction(UnaryInstruction.LRETURN);
376   }
377   else {
378       return new UnaryInstruction(UnaryInstruction.IRETURN);
379   }
380     }
381 
382     /**
383      * @return a default implementation for an abstract method
384      **/
385     private MethodInfo getMethodImplementation(Method method) {
386   
387   String desc = getDescriptor(method.getParameterTypes(), 
388             method.getReturnType());
389   
390   MethodAccessFlags access = new MethodAccessFlags((short)0);
391   access.setIsAbstract(false);
392   int mmod = method.getModifiers();
393   if (Modifier.isPublic(mmod)) {
394       access.setPublic();
395   }
396   else if (Modifier.isProtected(mmod)) {
397       access.setProtected();
398         }
399   //all other flags are not allowed when declared abstract
400   
401   System.out.println("IMplement methodS:"+method.getName());
402   MethodInfo methodImpl = new MethodInfo(access, method.getName(), desc);
403         
404   //all thrown exception where ignored, because no
405   //implementation throws an exception
406   
407   //add code attribute
408   methodImpl.
409       addAttribute(new 
410        AttributeInfo(getDefaultAttribute(method.
411                  getReturnType())));
412 
413   return methodImpl;
414     }
415 
416     /**
417      * @return the default implementation of a codeattribute. This 
418      * method should be averwritten to change the default implementation
419      * of abstract methods
420      * @param retType string of the basetype of the return type (see §4.3.2)
421      * @return a CodeAttribute
422      **/
423     protected CodeAttribute getDefaultAttribute(Class ret) {
424   Code code = new Code();
425   if (ret.isArray() || !ret.isPrimitive()) {
426       //it is an object or an array, return just null
427       //push null onto the stack
428       //print areturn
429       code.
430     addInstruction(new 
431              UnaryInstruction(UnaryInstruction.ACONST_NULL));
432   }
433   else if (Void.TYPE.isAssignableFrom(ret)) {
434       //void return type      
435       //print return
436   }
437   else if (Double.TYPE.isAssignableFrom(ret)) {
438       //double return 0
439       //push 0 onto the stack (dconst_0)
440       //print dreturn
441       code.addInstruction(new 
442         UnaryInstruction(UnaryInstruction.DCONST_0));
443   }
444   else if (Float.TYPE.isAssignableFrom(ret)) {
445       //float return 0      
446       //push 0 onto the stack (fconst_0)
447       //print freturn
448       code.addInstruction(new 
449         UnaryInstruction(UnaryInstruction.FCONST_0));
450   }
451   else if (Long.TYPE.isAssignableFrom(ret)) {
452       //long return 0
453       //push 0 onto the stack (lconst_0)
454       //print lreturn
455       code.addInstruction(new 
456         UnaryInstruction(UnaryInstruction.LCONST_0));
457   }
458   else {
459       //boolean, char, short, int, byte
460       //return 0
461       //push 0 onto the stack (iconst_0)
462       //print ireturn
463       code.addInstruction(new 
464         UnaryInstruction(UnaryInstruction.ICONST_0));
465   }
466 
467   code.addInstruction(getReturnInstruction(ret));
468   return new CodeAttribute(code);
469     }
470 
471     /**
472      * Write an array of bytes into an output file
473      * @param bytes the byte array to write
474      * @param name the classname
475      **/
476     private void writeClassFile(byte[] bytes, String name) throws IOException {
477   System.out.println("Write output file to:"+name);
478   FileOutputStream fileoutputstream = 
479       new FileOutputStream(name + ".class");
480   fileoutputstream.write(bytes);
481   fileoutputstream.close();
482     }
483 }