KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > spoon > jdiet > ASMJDietVerifier


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  * Contact: Lionel.Seinturier@lifl.fr
21  *
22  * Author: Eric Bruneton
23  * Author: Lionel Seinturier
24  */

25
26 package spoon.jdiet;
27
28 import java.io.File JavaDoc;
29 import java.io.FileInputStream JavaDoc;
30 import java.io.InputStream JavaDoc;
31 import java.util.Enumeration JavaDoc;
32 import java.util.HashMap JavaDoc;
33 import java.util.HashSet JavaDoc;
34 import java.util.Iterator JavaDoc;
35 import java.util.Map JavaDoc;
36 import java.util.Set JavaDoc;
37 import java.util.zip.ZipEntry JavaDoc;
38 import java.util.zip.ZipFile JavaDoc;
39
40 import org.apache.tools.ant.BuildException;
41 import org.apache.tools.ant.taskdefs.MatchingTask;
42 import org.objectweb.asm.AnnotationVisitor;
43 import org.objectweb.asm.Attribute;
44 import org.objectweb.asm.ClassAdapter;
45 import org.objectweb.asm.ClassReader;
46 import org.objectweb.asm.ClassVisitor;
47 import org.objectweb.asm.ClassWriter;
48 import org.objectweb.asm.FieldVisitor;
49 import org.objectweb.asm.Label;
50 import org.objectweb.asm.MethodAdapter;
51 import org.objectweb.asm.MethodVisitor;
52 import org.objectweb.asm.Opcodes;
53
54 /**
55  * An Ant task for checking that some given bytecode files do not contain calls
56  * to an unsupported Java API. This task is used for example that a bytecode is
57  * compliant with the J2ME CLDC configuration.
58  *
59  * @author Eric Bruneton
60  * @author Lionel Seinturier <Lionel.Seinturier@lifl.fr>
61  */

62 public class ASMJDietVerifier extends MatchingTask {
63
64   private File JavaDoc src;
65
66   private File JavaDoc cldcJar;
67
68   /**
69    * A set of strings describing the API supported by the cldc.jar library.
70    * The API includes public and protected methods and fields.
71    * Each string is of the form <classname>,<signature>.
72    * E.g. java/io/ByteArrayInputStream,read()I
73    */

74   // Set<String>
75
private Set JavaDoc cldcAPI;
76   
77   /**
78    * A map of the public and protected members (methods and fields) included in
79    * the cldc.jar library. The key is the class name (e.g.
80    * java/io/ByteArrayInputStream) and the value is the set of member signatures
81    * (e.g. read()I). This map is used to construct the cldcAPI set.
82    */

83   // Map<String,Set<String>>
84
private Map JavaDoc cldcMembers;
85   
86   /**
87    * A map of the super classes included in the cldc.jar library. The key is the
88    * class name and the value is a set of super classes.
89    */

90   // Map<String,Set<String>>
91
private Map JavaDoc cldcSupers;
92
93   private int errors;
94
95   public void setSrcdir (final File JavaDoc src) {
96     this.src = src;
97   }
98
99   public void setCldcjar (final File JavaDoc cldcJar) {
100     this.cldcJar = cldcJar;
101   }
102
103   /**
104    * Executes this task.
105    */

106
107   public void execute () {
108     if (src == null) {
109       throw new BuildException("srcdir must be specified");
110     }
111
112     try {
113       if (cldcJar != null) {
114         cldcAPI = new HashSet JavaDoc();
115         cldcMembers = new HashMap JavaDoc();
116         cldcSupers = new HashMap JavaDoc();
117         
118         ZipFile JavaDoc zf = new ZipFile JavaDoc(cldcJar);
119         Enumeration JavaDoc e = zf.entries();
120         while (e.hasMoreElements()) {
121           ZipEntry JavaDoc ze = (ZipEntry JavaDoc)e.nextElement();
122           if (ze.getName().endsWith(".class")) {
123             new ClassReader(zf.getInputStream(ze)).accept(new ClassAnalyzer(), true);
124           }
125         }
126         
127         /*
128          * Compute the transitive closure of the inheritance tree.
129          */

130         // Iterate over classes
131
for (Iterator JavaDoc iter = cldcSupers.keySet().iterator(); iter.hasNext();) {
132             
133             String JavaDoc clName = (String JavaDoc) iter.next();
134             Set JavaDoc superNames = (Set JavaDoc) cldcSupers.get(clName);
135             
136             int oldSize,newSize;
137             do {
138                 Set JavaDoc closure = new HashSet JavaDoc();
139                 
140                 // Iterate over super classes
141
for (Iterator JavaDoc iterator2 = superNames.iterator(); iterator2.hasNext();) {
142                     String JavaDoc superName = (String JavaDoc) iterator2.next();
143                     
144                     Set JavaDoc ssupers = (Set JavaDoc) cldcSupers.get(superName);
145                     if( ssupers != null ) {
146                         closure.addAll(ssupers);
147                     }
148                 }
149                 
150                 oldSize = superNames.size();
151                 superNames.addAll(closure);
152                 newSize = superNames.size();
153             }
154             while( oldSize != newSize );
155         }
156         
157         /*
158          * Add signatures for inherited members.
159          */

160         // Iterate over classes
161
for (Iterator JavaDoc iter = cldcSupers.keySet().iterator(); iter.hasNext();) {
162         
163             String JavaDoc clName = (String JavaDoc) iter.next();
164             Set JavaDoc superNames = (Set JavaDoc) cldcSupers.get(clName);
165             
166             // Iterate over super classes
167
for (Iterator JavaDoc iterator2 = superNames.iterator(); iterator2.hasNext();) {
168                 String JavaDoc superName = (String JavaDoc) iterator2.next();
169                 
170                 // members is null for java/lang/Object
171
Set JavaDoc members = (Set JavaDoc) cldcMembers.get(superName);
172                 if( members != null ) {
173                     
174                     // Iterate over members of super classes
175
for (Iterator JavaDoc iterator3 = members.iterator(); iterator3.hasNext();) {
176                         String JavaDoc member = (String JavaDoc) iterator3.next();
177                         
178                         // Add inherited members in the API
179
cldcAPI.add(clName+","+member);
180                     }
181                 }
182             }
183         }
184       }
185     } catch (Exception JavaDoc e) {
186       log(e.getMessage());
187     }
188
189     int total = 0;
190     String JavaDoc[] files = getDirectoryScanner(src).getIncludedFiles();
191     for (int i = 0; i < files.length; ++i) {
192       File JavaDoc srcFile = new File JavaDoc(src, files[i]);
193
194       ClassReader cr;
195       try {
196         InputStream JavaDoc is = new FileInputStream JavaDoc(srcFile);
197         cr = new ClassReader(is);
198       } catch (Exception JavaDoc e) {
199         log(e.getMessage());
200         continue;
201       }
202
203       ClassWriter cw = new ClassWriter(false);
204       ClassVerifier converter = new ClassVerifier(cw);
205       cr.accept(converter, true);
206
207       ++total;
208     }
209
210     if (errors > 0) {
211       throw new BuildException(errors+" errors");
212     } else if (total > 0) {
213       if (total == 1) {
214         log("1 class scanned");
215       } else {
216         log(total + " classes scanned");
217       }
218     }
219   }
220
221 /**
222  * @author Eric Bruneton
223  * @author Lionel Seinturier <Lionel.Seinturier@lifl.fr>
224  */

225 class ClassAnalyzer implements ClassVisitor, Opcodes {
226
227     private String JavaDoc name;
228
229     public void visit (
230       final int version,
231       final int access,
232       final String JavaDoc name,
233       final String JavaDoc signature,
234       final String JavaDoc superName,
235       final String JavaDoc[] interfaces)
236     {
237       this.name = name;
238       
239       Set JavaDoc supers = (Set JavaDoc) cldcSupers.get(name);
240       if( supers == null ) {
241           supers = new HashSet JavaDoc();
242           cldcSupers.put(name,supers);
243       }
244       supers.add(superName);
245     }
246     
247     public FieldVisitor visitField (
248       int access,
249       String JavaDoc name,
250       String JavaDoc desc,
251       String JavaDoc signature,
252       Object JavaDoc value)
253     {
254       FieldVisitor fv = null;
255       if ((access & (ACC_PUBLIC | ACC_PROTECTED)) != 0) {
256         cldcAPI.add(this.name+","+name);
257         addMember(this.name,name);
258       }
259       return fv;
260     }
261     
262     private void addMember( String JavaDoc clName, String JavaDoc memberName ) {
263         Set JavaDoc members = (Set JavaDoc) cldcMembers.get(clName);
264         if( members == null ) {
265             members = new HashSet JavaDoc();
266             cldcMembers.put(clName,members);
267         }
268         members.add(memberName);
269     }
270
271     public MethodVisitor visitMethod (
272       final int access,
273       final String JavaDoc name,
274       final String JavaDoc desc,
275       final String JavaDoc signature,
276       final String JavaDoc[] exceptions)
277     {
278       if ((access & (ACC_PUBLIC | ACC_PROTECTED)) != 0) {
279         cldcAPI.add(this.name+","+name+desc);
280         addMember(this.name,name+desc);
281       }
282       MethodVisitor mv = null;
283       return mv;
284     }
285
286     public void visitInnerClass (
287       final String JavaDoc name,
288       final String JavaDoc outerName,
289       final String JavaDoc innerName,
290       final int access)
291     {
292     }
293
294     public void visitEnd () {
295     }
296     
297       public void visitSource(String JavaDoc source, String JavaDoc debug) {
298       }
299   
300       public void visitOuterClass(String JavaDoc owner, String JavaDoc name, String JavaDoc desc) {
301       }
302   
303       public AnnotationVisitor visitAnnotation(String JavaDoc desc, boolean visible) {
304         return null;
305       }
306   
307       public void visitAttribute(Attribute attr) {
308       }
309   }
310
311 /**
312  * @author Eric Bruneton
313  * @author Lionel Seinturier <Lionel.Seinturier@lifl.fr>
314  */

315 class ClassVerifier extends ClassAdapter implements Opcodes {
316
317     private String JavaDoc name;
318
319     public ClassVerifier (ClassVisitor cv) {
320       super(cv);
321     }
322
323     public void visit (
324       final int version,
325       final int access,
326       final String JavaDoc name,
327       final String JavaDoc signature,
328       final String JavaDoc superName,
329       final String JavaDoc[] interfaces)
330     {
331       this.name = name;
332       
333       for (int i = 0; i < interfaces.length; i++) {
334         if( interfaces[i].startsWith("java/") ) {
335             if( ! cldcMembers.keySet().contains(interfaces[i]) ) {
336                 log(name + ": must not use " + interfaces[i] + "(not in CLDC API)");
337                 ++errors;
338             }
339         }
340     }
341       
342       cv.visit(version, access, name, signature, superName, interfaces);
343     }
344
345     
346     public FieldVisitor visitField (
347       int access,
348       String JavaDoc name,
349       String JavaDoc desc,
350       String JavaDoc signature,
351       Object JavaDoc value)
352     {
353       return cv.visitField(access, name, desc,signature, value);
354     }
355     
356     public MethodVisitor visitMethod (
357       final int access,
358       final String JavaDoc name,
359       final String JavaDoc desc,
360       final String JavaDoc signature,
361       final String JavaDoc[] exceptions)
362     {
363      return new CodeVerifier(
364         this, cv.visitMethod(access, name, desc, signature, exceptions));
365     }
366
367   }
368
369   class CodeVerifier extends MethodAdapter implements Opcodes {
370
371     private ClassVerifier c;
372     private String JavaDoc lastMethodCallInsn;
373     private boolean mustNotUseResult;
374
375     public CodeVerifier (ClassVerifier c, MethodVisitor mv) {
376       super(mv);
377       this.c = c;
378     }
379
380     private void check (int opcode) {
381       if (mustNotUseResult && opcode != POP) {
382         log(c.name + ": must not use result of " + lastMethodCallInsn);
383         ++errors;
384       }
385       mustNotUseResult = false;
386     }
387
388     public void visitInsn (final int opcode) {
389       check(opcode);
390       mv.visitInsn(opcode);
391     }
392
393     public void visitIntInsn (final int opcode, final int operand) {
394       check(opcode);
395       mv.visitIntInsn(opcode, operand);
396     }
397
398     public void visitVarInsn (final int opcode, final int var) {
399       check(opcode);
400       mv.visitVarInsn(opcode, var);
401     }
402
403     public void visitTypeInsn (final int opcode, final String JavaDoc desc) {
404       check(opcode);
405       mv.visitTypeInsn(opcode, desc);
406     }
407
408     public void visitFieldInsn (
409       final int opcode,
410       final String JavaDoc owner,
411       final String JavaDoc name,
412       final String JavaDoc desc)
413     {
414       check(opcode);
415       if (cldcAPI != null && owner.startsWith("java")) {
416         String JavaDoc key = owner+","+name;
417         if (!cldcAPI.contains(key)) {
418           log(c.name + ": must not use " + key + "(not in CLDC API)");
419           ++errors;
420         }
421       }
422       mv.visitFieldInsn(opcode, owner, name, desc);
423     }
424
425     public void visitMethodInsn (
426       final int opcode,
427       final String JavaDoc owner,
428       final String JavaDoc name,
429       final String JavaDoc desc)
430     {
431       check(opcode);
432       String JavaDoc key = owner + "," + name + desc;
433       if (cldcAPI != null && owner.startsWith("java")) {
434         if (!cldcAPI.contains(key)) {
435           log(c.name + ": must not use " + key + " (not in CLDC API)");
436           ++errors;
437         }
438       }
439       mv.visitMethodInsn(opcode, owner, name, desc);
440     }
441
442     public void visitJumpInsn (final int opcode, final Label label) {
443       check(opcode);
444       mv.visitJumpInsn(opcode, label);
445     }
446
447     public void visitLdcInsn (final Object JavaDoc cst) {
448       check(LDC);
449       mv.visitLdcInsn(cst);
450     }
451
452     public void visitIincInsn (final int var, final int increment) {
453       check(IINC);
454       mv.visitIincInsn(var, increment);
455     }
456
457     public void visitTableSwitchInsn (
458       final int min,
459       final int max,
460       final Label dflt,
461       final Label labels[])
462     {
463       check(TABLESWITCH);
464       mv.visitTableSwitchInsn(min, max, dflt, labels);
465     }
466
467     public void visitLookupSwitchInsn (
468       final Label dflt,
469       final int keys[],
470       final Label labels[])
471     {
472       check(LOOKUPSWITCH);
473       mv.visitLookupSwitchInsn(dflt, keys, labels);
474     }
475
476     public void visitMultiANewArrayInsn (final String JavaDoc desc, final int dims) {
477       check(MULTIANEWARRAY);
478       mv.visitMultiANewArrayInsn(desc, dims);
479     }
480   }
481 }
482
Popular Tags