KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > csdl > jblanket > modifier > ClassModifier


1 package csdl.jblanket.modifier;
2
3 import csdl.jblanket.JBlanketException;
4 import csdl.jblanket.methodset.MethodSetManager;
5 import csdl.jblanket.util.MethodCategories;
6
7 import java.io.File JavaDoc;
8 import java.io.IOException JavaDoc;
9
10 import org.apache.bcel.classfile.ClassParser;
11 import org.apache.bcel.classfile.JavaClass;
12 import org.apache.bcel.classfile.Method;
13 import org.apache.bcel.generic.ConstantPoolGen;
14 import org.apache.bcel.generic.MethodGen;
15 import org.apache.bcel.generic.ObjectType;
16 import org.apache.bcel.generic.Type;
17
18 /**
19  * Provides a Modifer for Java byte code in class files. Methods in a class are modified only
20  * once. However, even though a class was previously modified, it still needs to be processed by
21  * this class so that all of its methods can be recorded in the set of total methods.
22  *
23  * @author Joy M. Agustin
24  * @version $Id: ClassModifier.java,v 1.4 2005/02/19 05:55:19 timshadel Exp $
25  */

26 class ClassModifier {
27
28   /** Describes if JBlanket should execute in verbose mode */
29   private boolean verbose;
30   /** Grammar for names of test classes */
31   private String JavaDoc testGrammar;
32
33   /** Describes if one-line methods should be excluded from the coverage measurement */
34   private boolean excludeOneLineMethods;
35   /** Describes if constructors should be excluded from the coverage measurement */
36   private boolean excludeConstructors;
37   /** Describes if a file should be used to exclude methods from the coverage measurement */
38   private boolean excludeIndividualMethods;
39   
40   /** Counts the methods found in the system */
41   private MethodCounter counter;
42
43   /** File to modify */
44   private File JavaDoc classFile;
45   /** JavaClass for classFile */
46   private JavaClass clazz;
47   
48   /**
49    * Constructs a new ClassModifier object.
50  * @param verbose describes if JBlanke should execute in verbose mode.
51  * @param testGrammar the grammar describing test class names.
52  * @param excludeOneLineMethods describes exclusion of one-line methods.
53  * @param excludeConstructors describes exclusion of constructors.
54  * @param excludeIndividualMethods TODO
55  * @param counter the MethodCounter collecting all method type signatures.
56  * @param classFile the fully qualified path to a class file to process.
57    *
58    * @throws JBlanketException if unable to get byte code from <code>classFile</code>.
59    */

60   public ClassModifier(boolean verbose, String JavaDoc testGrammar, boolean excludeOneLineMethods,
61                         boolean excludeConstructors, boolean excludeIndividualMethods,
62                         MethodCounter counter, File JavaDoc classFile)
63       throws JBlanketException {
64
65     this.verbose = verbose;
66     this.testGrammar = testGrammar;
67  
68     this.excludeOneLineMethods = excludeOneLineMethods;
69     this.excludeConstructors = excludeConstructors;
70     this.excludeIndividualMethods = excludeIndividualMethods;
71  
72     this.counter = counter;
73  
74     this.classFile = classFile;
75
76     // retrieve class byte code -- throws IOException
77
try {
78       this.clazz = (new ClassParser(this.classFile.getAbsolutePath())).parse();
79     }
80     catch (IOException JavaDoc e) {
81       throw new JBlanketException("Unable to parse " + this.classFile.getAbsolutePath(), e);
82     }
83   }
84   
85   /**
86    * Constructs a new ClassModifier object.
87    *
88    * @param verbose describes if JBlanke should execute in verbose mode.
89    * @param counter the MethodCounter collecting all method type signatures.
90    * @param classFile the fully qualified path to a class file to process.
91    * @throws JBlanketException if unable to get byte code from <code>classFile</code>.
92    */

93   public ClassModifier(boolean verbose, MethodCounter counter, File JavaDoc classFile)
94       throws JBlanketException {
95     this(verbose, null, false, false, false, counter, classFile);
96   }
97   
98   /**
99    * Modifies byte code in the class represented by this ClassModifier.
100    *
101    * @throws JBlanketException if unable to store modified byte code.
102    */

103   public void modifyMethods() throws JBlanketException {
104
105     Method[] methods = clazz.getMethods();
106  
107     // count all methods in the class
108
this.counter.findAllMethods(clazz, this.excludeConstructors);
109  
110     // modify methods if they weren't previously modified
111
// if (!isModified()) {
112

113       // process methods
114
ConstantPoolGen pool = new ConstantPoolGen(clazz.getConstantPool());
115       for (int j = 0; j < methods.length; j++) {
116         MethodGen method = new MethodGen(methods[j], clazz.getClassName(), pool);
117
118         // TODO: Add "excluded individual methods"
119
MethodModifier methodModifier = new MethodModifier(this.verbose, this.testGrammar,
120                                                            this.excludeOneLineMethods,
121                                                            this.excludeIndividualMethods,
122                                                            this.excludeConstructors, method);
123         methods[j] = methodModifier.processMethod(pool, isModified());
124       }
125       clazz.setConstantPool(pool.getFinalConstantPool());
126       //}
127

128     // dump the modified class back into its current directory
129
try {
130       clazz.dump(this.classFile.getAbsoluteFile());
131     }
132     catch (IOException JavaDoc e) {
133       throw new JBlanketException("Unable to save modified file "
134                                   + this.classFile.getAbsolutePath());
135     }
136   }
137
138   /**
139    * Checks if a class has already been modified.
140    * <p>
141    * If <code>clazz</code> references the <code>MethodCollector.storeMethodTypeSignature</code>
142    * method, then all methods in the class were previously modified.
143    *
144    * NOTE: method is package private for testing, else should be private.
145    *
146    * @return true if the class was previously modified or cannot be modified, false otherwise.
147    */

148   boolean isModified() {
149
150     ConstantPoolGen pool = new ConstantPoolGen(clazz.getConstantPool());
151  
152     // will not modify native classes; abstract classes can have non-abstract methods.
153
// catch the abstract methods when modifying them.
154
if (clazz.isNative()) {
155       return true;
156     }
157  
158     Type[] parameters = new Type[]{Type.STRING, Type.STRING, new ObjectType("java.util.ArrayList"),
159                                    Type.STRING};
160     String JavaDoc methodSignature = Type.getMethodSignature(Type.VOID, parameters);
161
162     int result = pool.lookupMethodref("csdl.jblanket.modifier.MethodCollector",
163                                       "storeMethodTypeSignature", methodSignature);
164     return result != -1;
165   }
166   
167   /**
168    * Records the excluded methods in the class represented by this ClassModifier.
169    */

170   public void excludeMethods() {
171
172     Method[] methods = clazz.getMethods();
173
174     // process methods
175
ConstantPoolGen pool = new ConstantPoolGen(clazz.getConstantPool());
176     for (int j = 0; j < methods.length; j++) {
177       MethodGen method = new MethodGen(methods[j], clazz.getClassName(), pool);
178       MethodModifier methodModifier = new MethodModifier(this.verbose, this.testGrammar,
179                                                          this.excludeOneLineMethods,
180                                                          false, this.excludeConstructors, method);
181       methodModifier.excludeMethod(MethodSetManager.getInstance().getMethodSet(
182                                    MethodCategories.getInstance().getFileName("excludedFile")));
183     }
184   }
185 }
186
Popular Tags