KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > tools > verifier > apiscan > classfile > ASMClosureCompilerImpl


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 /*
25  * ASMClosureCompilerImpl.java
26  *
27  * Created on August 13, 2004, 3:34 PM
28  */

29
30 package com.sun.enterprise.tools.verifier.apiscan.classfile;
31
32 import java.io.IOException JavaDoc;
33 import java.util.*;
34 import java.util.logging.Level JavaDoc;
35
36 /**
37  * An implementation of {@link ClosureCompilerImplBase} based on
38  * ASM.
39  *
40  * It is not a public class because I expect users to use this class via
41  * the bridge setup from {@link ClosureCompilerImpl}.
42  * It extends the common implementation from ClosureCompilerImplBase.
43  * @author Sanjeeb.Sahoo@Sun.COM
44  */

45 class ASMClosureCompilerImpl extends ClosureCompilerImplBase {
46
47     private Collection<MethodRef> methodReferences = new HashSet<MethodRef>();
48
49     private HashSet<MethodRef> visitedMethods = new HashSet<MethodRef>();
50
51     private Stack<MethodRef> callStack = new Stack<MethodRef>();
52
53     // holds result of current buildClosure() method
54
private boolean result;
55
56     private HashSet<String JavaDoc> closure = new HashSet<String JavaDoc>();
57
58     //map of refencing path to list of not found classes.
59
private Map<String JavaDoc, List<String JavaDoc>> failed = new HashMap<String JavaDoc, List<String JavaDoc>>();
60
61     private static final String JavaDoc myClassName = "ASMClosureCompilerImpl"; // NOI18N
62

63     /**
64      * @param loader the ClassFileLoader that is used to load the referenced
65      * classes.
66      */

67     public ASMClosureCompilerImpl(ClassFileLoader loader) {
68         super(loader);
69     }
70
71     private void resetResult() {
72         logger.entering("ASMClosureCompilerImpl", "resetResult", // NOI18N
73
new Object JavaDoc[]{});
74         result = true;
75     }
76
77     private void setResult(boolean newresult){
78         result = result && newresult;
79     }
80
81     private boolean getResult() {
82         return result;
83     }
84
85     /**
86      * {@inheritDoc}
87      */

88     public boolean buildClosure(String JavaDoc className) {
89         logger.entering(myClassName, "buildClosure", className); // NOI18N
90
resetResult(); // at the entry of this public method, we reset result.
91
if (needToBuildClosure(className)) {
92             visitedClasses.add(className); // yes, we add before visting
93
ClassFile cf = load(className);
94             if(cf==null){
95                 return false;
96             }
97             // top level methods whose closure needs to be calculated.
98
// TODO: We must get precise list of methods.
99
Collection<? extends Method> methods = cf.getMethods();
100             for(Method next:methods){
101                 methodReferences.add(next.getSelfReference());
102                 buildClosure(next);
103             }
104         }
105         return getResult();
106     }
107
108     private void buildClosure(Method m) {
109         MethodRef methodReference = m.getSelfReference();
110         logger.entering("ASMClosureCompilerImpl", "buildClosure", // NOI18N
111
new Object JavaDoc[]{methodReference});
112         callStack.push(methodReference);
113         if (needToBuildClosure(methodReference)) {
114             visitedMethods.add(methodReference);
115             Collection<MethodRef> methodRefs = m.getReferencedMethods();
116             methodReferences.addAll(methodRefs);
117             for(MethodRef nextMethodRef : methodRefs) {
118                 if (!needToBuildClosure(nextMethodRef)) continue;
119                 ClassFile cf = load(Util.convertToExternalClassName
120                         (nextMethodRef.getOwningClassName()));
121                 if (cf == null) {
122                     continue; // no need to call handleFailure() as it is done by this.load()
123
}
124                 Method nextMethod = cf.getMethod(nextMethodRef);
125                 if(nextMethod==null){
126                     handleFailure(nextMethodRef);
127                     continue;
128                 }
129                 buildClosure(nextMethod);//recurssive call
130
} // for
131
// now go thru' all the classes that will be loaded when this
132
// method is called.
133
for(String JavaDoc className : m.getReferencedClasses()){
134                 String JavaDoc externalClassName = Util.convertToExternalClassName(className);
135                 if(!needToBuildClosure(externalClassName)) continue;
136                 load(externalClassName);
137             }
138         }
139         callStack.pop();
140     }
141
142     /**
143      * load class with given name. It also recurssively loads all classes in the
144      * super class chain and interfaces implemented by this class and
145      * its super classes, until it reaches a class which is found in the
146      * excluded list. It also builds closure of each of the class's clinit method.
147      *
148      * @param className name of class in external format.
149      * @return ClassFile representing this class name,
150      * It returns null if class has been already loaded or need not be loaded
151      * because it is an excluded class or could not be loaded. If class could
152      * could not be loaded, it calls appropriate handleFailure().
153      * @see #needToLoad(String)
154      */

155     protected ClassFile load(String JavaDoc className) {
156         logger.entering("ASMClosureCompilerImpl", "load", // NOI18N
157
new Object JavaDoc[]{className});
158         ClassFile cf = null;
159         try{
160             cf = loader.load(className);
161         }catch(IOException JavaDoc e){
162             handleFailure(className);
163         }
164         if((cf!=null) && needToLoad(className)) {
165             closure.add(className); // yes we add before actually loading.
166
MethodRef clinitMethodRef =
167                     new MethodRef(Util.convertToInternalClassName(className),
168                             MethodRef.CLINIT_NAME,
169                             MethodRef.CLINIT_DESC);
170             Method clinitMethod = cf.getMethod(clinitMethodRef);
171             try{
172                 // See we push clinitMethodRef here so that we can display
173
// useful error to user even during class loading.
174
callStack.push(clinitMethodRef);
175                 String JavaDoc superClassName = cf.getNameOfSuperClass();
176                 if(superClassName!=null && needToBuildClosure(superClassName)) { // super class of java.lang.Object is null
177
load(superClassName); //recurssive call
178
}
179                 for(String JavaDoc interfaceClassName : cf.getNamesOfInterfaces()){
180                     if(needToBuildClosure(interfaceClassName)) {
181                         load(interfaceClassName); // recurssive call
182
}
183                 }
184             }finally{
185                 // pop callStack before buildClosure is called for clinit
186
callStack.pop();
187             }
188             if(clinitMethod!=null) {
189                 methodReferences.add(clinitMethodRef);
190                 buildClosure(clinitMethod); // recurssive call
191
}
192         }
193         logger.exiting("ASMClosureCompilerImpl", "load", cf==null?"null":cf.getName()); // NOI18N
194
return cf;
195     }
196
197     private void handleFailure(MethodRef mr){
198         logger.logp(Level.WARNING, "ASMClosureCompilerImpl", "handleFailure",
199                 getClass().getName() + ".exception1", new Object JavaDoc[]{mr.toString()});
200 // setResult(false);
201
// TODO: We should look for base class methods
202
}
203
204     /**
205      * @param referencedClass is the name of the class in external format.
206      */

207     private void handleFailure(String JavaDoc referencedClass) {
208         logger.entering("ASMClosureCompilerImpl", "handleFailure", // NOI18N
209
new Object JavaDoc[]{referencedClass});
210         setResult(false);
211         String JavaDoc referencingPath = "";
212         try {
213             StringBuilder JavaDoc referencingPathBuffer = new StringBuilder JavaDoc();
214             for (MethodRef m : callStack) {
215                 if (referencingPathBuffer.length() != 0)
216                     referencingPathBuffer.append("->"); // NOI18N
217
referencingPathBuffer.append(m);
218             }
219             referencingPath = referencingPathBuffer.toString();
220         } catch (EmptyStackException e) {
221         }
222         List<String JavaDoc> failedList = failed.get(referencingPath);
223         if (failedList == null) {
224             failedList = new ArrayList<String JavaDoc>();
225             failed.put(referencingPath, failedList);
226         }
227         failedList.add(referencedClass);
228     }
229
230     /**
231      * {@inheritDoc}
232      */

233     public Collection getClosure() {
234         return Collections.unmodifiableCollection(methodReferences);
235     }
236
237     /**
238      * {@inheritDoc}
239      */

240     public Map getFailed() {
241         return Collections.unmodifiableMap(failed);
242     }
243     
244     /**
245      * Reset the closure for next closure computation.
246      * Clear the internal cache. It includes the result it has collected since
247      * last reset(). But it does not clear the excludedd list. If you want to
248      * reset the excluded list, create a new ClosureCompiler.
249      */

250     public void reset() {
251         methodReferences.clear();
252         visitedClasses.clear();
253         failed.clear();
254         closure.clear();
255     }
256
257     /**
258      * @param className name of class in external format.
259      * @return
260      */

261     protected boolean needToLoad(String JavaDoc className) {
262         return !closure.contains(className);
263     }
264
265     protected boolean needToBuildClosure(MethodRef methodRef) {
266         boolean result = true;
267         final String JavaDoc owningClassName = methodRef.getOwningClassName();
268         if (visitedMethods.contains(methodRef))
269             result = false;
270         else if (excludedClasses.contains(owningClassName)) {
271             result = false;
272         } else if (excludedPackages.contains(getPackageName(owningClassName))) {
273             result = false;
274         } else {
275             for (Iterator i = excludedPatterns.iterator(); i.hasNext();) {
276                 String JavaDoc pattern = (String JavaDoc) i.next();
277                 if (owningClassName.startsWith(pattern)) {
278                     result = false;
279                     break;
280                 }
281             }
282         }
283         logger.logp(Level.FINEST, myClassName, "needToBuildClosure", // NOI18N
284
methodRef + " " + result); // NOI18N
285
return result;
286     }
287
288     // used for pretty printing
289
public String JavaDoc toString() {
290         StringBuilder JavaDoc sb=new StringBuilder JavaDoc();
291         if(logger.isLoggable(Level.FINER)){
292             sb.append("\n<Closure>"); // NOI18N
293

294             sb.append("\n\t<ExcludedClasses>"); // NOI18N
295
for(Iterator i=excludedClasses.iterator(); i.hasNext();) {
296                 sb.append("\n\t\t"); // NOI18N
297
sb.append((String JavaDoc)i.next());
298             }
299             sb.append("\n\t</ExcludedClasses>"); // NOI18N
300

301             sb.append("\n\t<ExcludedPackages>"); // NOI18N
302
for(Iterator i=excludedPackages.iterator(); i.hasNext();){
303                 sb.append("\n\t\t"); // NOI18N
304
sb.append((String JavaDoc)i.next());
305             }
306             sb.append("\n\t</ExcludedPackages>"); // NOI18N
307

308             sb.append("\n\t<ExcludedPatterns>"); // NOI18N
309
for(Iterator i=excludedPatterns.iterator(); i.hasNext();){
310                 sb.append("\n\t\t"); // NOI18N
311
sb.append((String JavaDoc)i.next());
312             }
313             sb.append("\n\t</ExcludedPatterns>"); // NOI18N
314

315             sb.append("\n\t<Methods>"); // NOI18N
316
for(MethodRef m : methodReferences){
317                 sb.append("\n\t\t"); // NOI18N
318
sb.append(m);
319             }
320             sb.append("\n\t</Methods>"); // NOI18N
321

322             sb.append("\n\t<Closure>"); // NOI18N
323
for(String JavaDoc c : closure){
324                 sb.append("\n\t\t"); // NOI18N
325
sb.append(c);
326             }
327             sb.append("\n\t</Closure>"); // NOI18N
328
}
329         sb.append("\n\t<Failed>"); // NOI18N
330
for(Iterator i=failed.entrySet().iterator(); i.hasNext();) {
331             Map.Entry referencingPathToFailedList=(Map.Entry)i.next();
332             sb.append("\n\t\t"); // NOI18N
333
sb.append("<ReferencingPath>"); // NOI18N
334
sb.append("\n\t\t\t"); // NOI18N
335
sb.append(referencingPathToFailedList.getKey());
336             sb.append("\n\t\t"); // NOI18N
337
sb.append("</ReferencingPath>"); // NOI18N
338
sb.append("\n\t\t"); // NOI18N
339
sb.append("<Classes>"); // NOI18N
340
for(Iterator iii=((List)referencingPathToFailedList.getValue()).iterator(); iii.hasNext();){
341                 sb.append("\n\t\t\t"); // NOI18N
342
sb.append((String JavaDoc)iii.next());
343             }
344             sb.append("\n\t\t"); // NOI18N
345
sb.append("</Classes>"); // NOI18N
346
}
347         sb.append("\n\t</Failed>"); // NOI18N
348
if(logger.isLoggable(Level.FINER)){
349             sb.append("\n</Closure>"); // NOI18N
350
}
351         return sb.toString();
352     }
353
354 }
355
Popular Tags