FileDocCategorySizeDatePackage
ASMClosureCompilerImpl.javaAPI DocGlassfish v2 API14562Fri May 04 22:33:24 BST 2007com.sun.enterprise.tools.verifier.apiscan.classfile

ASMClosureCompilerImpl

public class ASMClosureCompilerImpl extends ClosureCompilerImplBase
An implementation of {@link ClosureCompilerImplBase} based on ASM. It is not a public class because I expect users to use this class via the bridge setup from {@link ClosureCompilerImpl}. It extends the common implementation from ClosureCompilerImplBase.
author
Sanjeeb.Sahoo@Sun.COM

Fields Summary
private Collection
methodReferences
private HashSet
visitedMethods
private Stack
callStack
private boolean
result
private HashSet
closure
private Map
failed
private static final String
myClassName
Constructors Summary
public ASMClosureCompilerImpl(ClassFileLoader loader)

param
loader the ClassFileLoader that is used to load the referenced classes.

 // NOI18N

                                   
       
        super(loader);
    
Methods Summary
public booleanbuildClosure(java.lang.String className)
{@inheritDoc}

        logger.entering(myClassName, "buildClosure", className); // NOI18N
        resetResult(); // at the entry of this public method, we reset result.
        if (needToBuildClosure(className)) {
            visitedClasses.add(className); // yes, we add before visting
            ClassFile cf = load(className);
            if(cf==null){
                return false;
            }
            // top level methods whose closure needs to be calculated.
            // TODO: We must get precise list of methods.
            Collection<? extends Method> methods = cf.getMethods();
            for(Method next:methods){
                methodReferences.add(next.getSelfReference());
                buildClosure(next);
            }
        }
        return getResult();
    
private voidbuildClosure(Method m)

        MethodRef methodReference = m.getSelfReference();
        logger.entering("ASMClosureCompilerImpl", "buildClosure", // NOI18N
                new Object[]{methodReference});
        callStack.push(methodReference);
        if (needToBuildClosure(methodReference)) {
            visitedMethods.add(methodReference);
            Collection<MethodRef> methodRefs = m.getReferencedMethods();
            methodReferences.addAll(methodRefs);
            for(MethodRef nextMethodRef : methodRefs) {
                if (!needToBuildClosure(nextMethodRef)) continue;
                ClassFile cf = load(Util.convertToExternalClassName
                        (nextMethodRef.getOwningClassName()));
                if (cf == null) {
                    continue; // no need to call handleFailure() as it is done by this.load()
                }
                Method nextMethod = cf.getMethod(nextMethodRef);
                if(nextMethod==null){
                    handleFailure(nextMethodRef);
                    continue;
                }
                buildClosure(nextMethod);//recurssive call
            } // for
            // now go thru' all the classes that will be loaded when this
            // method is called.
            for(String className : m.getReferencedClasses()){
                String externalClassName = Util.convertToExternalClassName(className);
                if(!needToBuildClosure(externalClassName)) continue;
                load(externalClassName);
            }
        }
        callStack.pop();
    
public java.util.CollectiongetClosure()
{@inheritDoc}

        return Collections.unmodifiableCollection(methodReferences);
    
public java.util.MapgetFailed()
{@inheritDoc}

        return Collections.unmodifiableMap(failed);
    
private booleangetResult()

        return result;
    
private voidhandleFailure(MethodRef mr)

        logger.logp(Level.WARNING, "ASMClosureCompilerImpl", "handleFailure", 
                getClass().getName() + ".exception1", new Object[]{mr.toString()});
//        setResult(false);
        // TODO: We should look for base class methods
    
private voidhandleFailure(java.lang.String referencedClass)

param
referencedClass is the name of the class in external format.

        logger.entering("ASMClosureCompilerImpl", "handleFailure", // NOI18N
                new Object[]{referencedClass});
        setResult(false);
        String referencingPath = "";
        try {
            StringBuilder referencingPathBuffer = new StringBuilder();
            for (MethodRef m : callStack) {
                if (referencingPathBuffer.length() != 0)
                    referencingPathBuffer.append("->"); // NOI18N
                referencingPathBuffer.append(m);
            }
            referencingPath = referencingPathBuffer.toString();
        } catch (EmptyStackException e) {
        }
        List<String> failedList = failed.get(referencingPath);
        if (failedList == null) {
            failedList = new ArrayList<String>();
            failed.put(referencingPath, failedList);
        }
        failedList.add(referencedClass);
    
protected ClassFileload(java.lang.String className)
load class with given name. It also recurssively loads all classes in the super class chain and interfaces implemented by this class and its super classes, until it reaches a class which is found in the excluded list. It also builds closure of each of the class's clinit method.

param
className name of class in external format.
return
ClassFile representing this class name, It returns null if class has been already loaded or need not be loaded because it is an excluded class or could not be loaded. If class could could not be loaded, it calls appropriate handleFailure().
see
#needToLoad(String)

        logger.entering("ASMClosureCompilerImpl", "load", // NOI18N
                new Object[]{className});
        ClassFile cf = null;
        try{
            cf = loader.load(className);
        }catch(IOException e){
            handleFailure(className);
        }
        if((cf!=null) && needToLoad(className)) {
            closure.add(className); // yes we add before actually loading.
            MethodRef clinitMethodRef =
                    new MethodRef(Util.convertToInternalClassName(className),
                            MethodRef.CLINIT_NAME,
                            MethodRef.CLINIT_DESC);
            Method clinitMethod  = cf.getMethod(clinitMethodRef);
            try{
                // See we push clinitMethodRef here so that we can display
                // useful error to user even during class loading.
                callStack.push(clinitMethodRef);
                String superClassName = cf.getNameOfSuperClass();
                if(superClassName!=null && needToBuildClosure(superClassName)) { // super class of java.lang.Object is null
                    load(superClassName); //recurssive call
                }
                for(String interfaceClassName : cf.getNamesOfInterfaces()){
                    if(needToBuildClosure(interfaceClassName)) {
                        load(interfaceClassName); // recurssive call
                    }
                }
            }finally{
                // pop callStack before buildClosure is called for clinit
                callStack.pop();
            }
            if(clinitMethod!=null) {
                methodReferences.add(clinitMethodRef);
                buildClosure(clinitMethod); // recurssive call
            }
        }
        logger.exiting("ASMClosureCompilerImpl", "load", cf==null?"null":cf.getName()); // NOI18N
        return cf;
    
protected booleanneedToBuildClosure(MethodRef methodRef)

        boolean result = true;
        final String owningClassName = methodRef.getOwningClassName();
        if (visitedMethods.contains(methodRef))
            result = false;
        else if (excludedClasses.contains(owningClassName)) {
            result = false;
        } else if (excludedPackages.contains(getPackageName(owningClassName))) {
            result = false;
        } else {
            for (Iterator i = excludedPatterns.iterator(); i.hasNext();) {
                String pattern = (String) i.next();
                if (owningClassName.startsWith(pattern)) {
                    result = false;
                    break;
                }
            }
        }
        logger.logp(Level.FINEST, myClassName, "needToBuildClosure", // NOI18N
                methodRef + " " + result); // NOI18N
        return result;
    
protected booleanneedToLoad(java.lang.String className)

param
className name of class in external format.
return

        return !closure.contains(className);
    
public voidreset()
Reset the closure for next closure computation. Clear the internal cache. It includes the result it has collected since last reset(). But it does not clear the excludedd list. If you want to reset the excluded list, create a new ClosureCompiler.

        methodReferences.clear();
        visitedClasses.clear();
        failed.clear();
        closure.clear();
    
private voidresetResult()

        logger.entering("ASMClosureCompilerImpl", "resetResult", // NOI18N
                new Object[]{});
        result = true;
    
private voidsetResult(boolean newresult)

        result = result && newresult;
    
public java.lang.StringtoString()

        StringBuilder sb=new StringBuilder();
        if(logger.isLoggable(Level.FINER)){
            sb.append("\n<Closure>"); // NOI18N

            sb.append("\n\t<ExcludedClasses>"); // NOI18N
            for(Iterator i=excludedClasses.iterator(); i.hasNext();) {
                sb.append("\n\t\t"); // NOI18N
                sb.append((String)i.next());
            }
            sb.append("\n\t</ExcludedClasses>"); // NOI18N

            sb.append("\n\t<ExcludedPackages>"); // NOI18N
            for(Iterator i=excludedPackages.iterator(); i.hasNext();){
                sb.append("\n\t\t"); // NOI18N
                sb.append((String)i.next());
            }
            sb.append("\n\t</ExcludedPackages>"); // NOI18N
            
            sb.append("\n\t<ExcludedPatterns>"); // NOI18N
            for(Iterator i=excludedPatterns.iterator(); i.hasNext();){
                sb.append("\n\t\t"); // NOI18N
                sb.append((String)i.next());
            }
            sb.append("\n\t</ExcludedPatterns>"); // NOI18N
            
            sb.append("\n\t<Methods>"); // NOI18N
            for(MethodRef m : methodReferences){
                sb.append("\n\t\t"); // NOI18N
                sb.append(m);
            }
            sb.append("\n\t</Methods>"); // NOI18N

            sb.append("\n\t<Closure>"); // NOI18N
            for(String c : closure){
                sb.append("\n\t\t"); // NOI18N
                sb.append(c);
            }
            sb.append("\n\t</Closure>"); // NOI18N
        }
        sb.append("\n\t<Failed>"); // NOI18N
        for(Iterator i=failed.entrySet().iterator(); i.hasNext();) {
            Map.Entry referencingPathToFailedList=(Map.Entry)i.next();
            sb.append("\n\t\t"); // NOI18N
            sb.append("<ReferencingPath>"); // NOI18N
            sb.append("\n\t\t\t"); // NOI18N
            sb.append(referencingPathToFailedList.getKey());
            sb.append("\n\t\t"); // NOI18N
            sb.append("</ReferencingPath>"); // NOI18N
            sb.append("\n\t\t"); // NOI18N
            sb.append("<Classes>"); // NOI18N
            for(Iterator iii=((List)referencingPathToFailedList.getValue()).iterator(); iii.hasNext();){
                sb.append("\n\t\t\t"); // NOI18N
                sb.append((String)iii.next());
            }
            sb.append("\n\t\t"); // NOI18N
            sb.append("</Classes>"); // NOI18N
        }
        sb.append("\n\t</Failed>"); // NOI18N
        if(logger.isLoggable(Level.FINER)){
            sb.append("\n</Closure>"); // NOI18N
        }
        return sb.toString();