Package org.jvnet.hk2.generator.internal

Source Code of org.jvnet.hk2.generator.internal.Utilities$GenerateServiceFromMethodVisitor

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package org.jvnet.hk2.generator.internal;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

import javax.inject.Named;
import javax.inject.Qualifier;
import javax.inject.Scope;
import javax.inject.Singleton;

import org.glassfish.hk2.api.Context;
import org.glassfish.hk2.api.ErrorService;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.Metadata;
import org.glassfish.hk2.api.PerLookup;
import org.glassfish.hk2.api.Proxiable;
import org.glassfish.hk2.api.Rank;
import org.jvnet.hk2.annotations.Contract;
import org.jvnet.hk2.annotations.ContractsProvided;
import org.glassfish.hk2.external.org.objectweb.asm.AnnotationVisitor;
import org.glassfish.hk2.external.org.objectweb.asm.ClassReader;
import org.glassfish.hk2.external.org.objectweb.asm.MethodVisitor;

/**
* @author jwells
*
*/
public class Utilities {
    private final static String DOT_CLASS = ".class";
    private final static String CONTRACT_WITH_SLASHES = "L" + Contract.class.getName().replace('.', '/') + ";";
    private final static String SCOPE_WITH_SLASHES = "L" + Scope.class.getName().replace('.', '/') + ";";
    private final static String QUALIFIER_WITH_SLASHES = "L" + Qualifier.class.getName().replace('.', '/') + ";";
    private final static String METHOD_GENERATOR_WITH_SLASHES = "Lorg/jvnet/hk2/config/GenerateServiceFromMethod;";
    private final static String GENERATOR_NAME_FIELD_WITH_SLASHES = "Lorg/jvnet/hk2/config/GeneratedServiceName;";
   
    private final static String METADATA_DESC = "Lorg/glassfish/hk2/api/Metadata;";
   
    private final Map<String, Boolean> ISA_CONTRACT = new HashMap<String, Boolean>();
    private final Map<String, Boolean> ISA_SCOPE = new HashMap<String, Boolean>();
    private final Map<String, Boolean> ISA_QUALIFIER = new HashMap<String, Boolean>();
    private final Map<String, String> FOUND_SUPERCLASS = new HashMap<String, String>()// Terminal is null
    private final Map<String, Set<String>> FOUND_INTERFACES = new HashMap<String, Set<String>>();
    private final Map<String, GenerateMethodAnnotationData> FOUND_GENERATORS = new HashMap<String, GenerateMethodAnnotationData>();
   
    // Map from scope or qualifier name to method name to metadata key value
    private final Map<String, Map<String, String>> METADATA =
            new HashMap<String, Map<String, String>>();
   
    private final boolean verbose;
    private final String searchPath;
   
    private final static String CONFIGURED_CONTRACT = "org.jvnet.hk2.config.Configured";
   
    private final static List<KnownClassData> KNOWN_DATA = new LinkedList<KnownClassData>();
   
    static {
        Set<String> empty = Collections.emptySet();
       
        // Factory
        KNOWN_DATA.add(new KnownClassData(Factory.class.getName(),
                true, // isa_contract
                false, // isa_scope
                false, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
       
        // Context
        KNOWN_DATA.add(new KnownClassData(Context.class.getName(),
                true, // isa_contract
                false, // isa_scope
                false, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
       
        // ErrorService
        KNOWN_DATA.add(new KnownClassData(ErrorService.class.getName(),
                true, // isa_contract
                false, // isa_scope
                false, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
       
        // Singleton
        KNOWN_DATA.add(new KnownClassData(Singleton.class.getName(),
                false, // isa_contract
                true, // isa_scope
                false, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
       
        // PerLookup
        KNOWN_DATA.add(new KnownClassData(PerLookup.class.getName(),
                false, // isa_contract
                true, // isa_scope
                false, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
       
        // Named
        KNOWN_DATA.add(new KnownClassData(Named.class.getName(),
                false, // isa_contract
                false, // isa_scope
                true, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
       
        // Contract
        KNOWN_DATA.add(new KnownClassData(Contract.class.getName(),
                false, // isa_contract
                false, // isa_scope
                false, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
       
        // @Configured
        KNOWN_DATA.add(new KnownClassData(CONFIGURED_CONTRACT,
                true, // isa_contract
                false, // isa_scope
                false, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
       
        // Scope
        KNOWN_DATA.add(new KnownClassData(Scope.class.getName(),
                false, // isa_contract
                false, // isa_scope
                false, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
       
        // Target
        KNOWN_DATA.add(new KnownClassData(Target.class.getName(),
                false, // isa_contract
                false, // isa_scope
                false, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
       
        // Retention
        KNOWN_DATA.add(new KnownClassData(Retention.class.getName(),
                false, // isa_contract
                false, // isa_scope
                false, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
       
        // Proxiable
        KNOWN_DATA.add(new KnownClassData(Proxiable.class.getName(),
                false, // isa_contract
                false, // isa_scope
                false, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
       
        // Annotation
        KNOWN_DATA.add(new KnownClassData(Annotation.class.getName(),
                false, // isa_contract
                false, // isa_scope
                false, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
       
        // Qualifier
        KNOWN_DATA.add(new KnownClassData(Qualifier.class.getName(),
                false, // isa_contract
                false, // isa_scope
                false, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
       
        // Documented
        KNOWN_DATA.add(new KnownClassData(Documented.class.getName(),
                false, // isa_contract
                false, // isa_scope
                false, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
       
        // Inherited
        KNOWN_DATA.add(new KnownClassData(Inherited.class.getName(),
                false, // isa_contract
                false, // isa_scope
                false, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
       
        // Inherited
        KNOWN_DATA.add(new KnownClassData(ContractsProvided.class.getName(),
                false, // isa_contract
                false, // isa_scope
                false, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
       
        // Rank
        KNOWN_DATA.add(new KnownClassData(Rank.class.getName(),
                false, // isa_contract
                false, // isa_scope
                false, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
       
        // Metadata
        KNOWN_DATA.add(new KnownClassData(Metadata.class.getName(),
                false, // isa_contract
                false, // isa_scope
                false, // isa_qualifier
                null,  // superclass
                empty  // interfaces
                ));
               
    }
   
    /* package */ Utilities(boolean verbose, String searchPath) {
        this.verbose = verbose;
        this.searchPath = searchPath;
       
        // We can pre-load the cache with some obvious ones and thus reduce searching quite a bit
        for (KnownClassData kcd : KNOWN_DATA) {
            ISA_CONTRACT.put(kcd.getClazz(), kcd.isIsa_contract());
            ISA_SCOPE.put(kcd.getClazz(), kcd.isIsa_scope());
            ISA_QUALIFIER.put(kcd.getClazz(), kcd.isIsa_qualifier());
            FOUND_SUPERCLASS.put(kcd.getClazz(), kcd.getSuperclass());
            FOUND_INTERFACES.put(kcd.getClazz(), kcd.getiFaces());
            FOUND_GENERATORS.put(kcd.getClazz(), null);
        }
       
        if (verbose && searchPath != null) {
            System.out.println("The elements of the path that will be searched is:");
            StringTokenizer st = new StringTokenizer(searchPath, File.pathSeparator);
            int lcv = 1;
            while (st.hasMoreTokens()) {
                String pathElement = st.nextToken();
               
                System.out.println(" " + lcv++ + ". " + pathElement);
            }
            System.out.println("Finished printing search path elements");
           
        }
    }
   
    /**
     * Will look for a file on a last-ditch sort of effort using the searchHere thing (jar or directory)
     * and then also in the classpath
     *
     * @param searchHere
     * @param dotDelimitedName
     * @param searchClassPath true if the classpath should be searched as well
     * @return an IOStream if the file could be located
     * @throws IOException
     */
    private InputStream findClass(File searchHere, String dotDelimitedName, boolean searchClassPath, String calledFrom) throws IOException {
        if (verbose && searchClassPath) {
            System.out.println("Looking for " + dotDelimitedName + " for discovery of " + calledFrom);
        }
       
        if (searchHere.isDirectory()) {
            String properPathName = dotDelimitedName.replace('.', File.separatorChar) + DOT_CLASS;
           
            File fullFile = new File(searchHere, properPathName);
           
            if (fullFile.exists()) {
                if (verbose) {
                    System.out.println("Found " + dotDelimitedName + " in " + searchHere.getAbsolutePath() + " for " + calledFrom);
                }
                return new FileInputStream(fullFile);
            }
        }
        else {
            JarFile jar = new JarFile(searchHere);
           
            String entryName = dotDelimitedName.replace('.', '/') + DOT_CLASS;
            ZipEntry entry = jar.getEntry(entryName);
            if (entry != null) {
                if (verbose) {
                    System.out.println("Found " + dotDelimitedName + " in jar " + searchHere.getAbsolutePath() + " for " + calledFrom);
                }
               
                return jar.getInputStream(entry);
            }
        }
       
        if (!searchClassPath) return null;
       
        // Handle classpath
        String classpath = searchPath;
        if (classpath == null) return null;
       
        StringTokenizer st = new StringTokenizer(classpath, File.pathSeparator);
        while (st.hasMoreTokens()) {
            String pathElement = st.nextToken();
           
            File nextSearchGuy = new File(pathElement);
            InputStream is = findClass(nextSearchGuy, dotDelimitedName, false, calledFrom);
            if (is != null) {
                return is;
            }
        }
       
        if (verbose) {
            System.out.println("Did not find " + dotDelimitedName + " in classpath for " + calledFrom);
        }
        return null;
    }
   
    private void nullCaches(String dotDelimitedName) {
        ISA_CONTRACT.put(dotDelimitedName, false);
        ISA_SCOPE.put(dotDelimitedName, false);
        ISA_QUALIFIER.put(dotDelimitedName, false);
        FOUND_SUPERCLASS.put(dotDelimitedName, null);
        FOUND_GENERATORS.put(dotDelimitedName, null);
    }
   
    /**
     * Returns true if the given class is a contract
     *
     * @param searchHere The file or jar to look in
     * @param dotDelimitedName The fully qualified class name to look for
     * @return true if this can determine that this is a contract
     */
    private boolean isClassAContract(File searchHere, String dotDelimitedName) {
        if (ISA_CONTRACT.containsKey(dotDelimitedName)) {
            return ISA_CONTRACT.get(dotDelimitedName);
        }
       
        InputStream is = null;
        try {
            is = findClass(searchHere, dotDelimitedName, true, "isaContract");
            if (is == null) {
                nullCaches(dotDelimitedName);
               
                return false;
            }
           
            ClassReader reader = new ClassReader(is);
           
            ContractClassVisitor ccv = new ContractClassVisitor(searchHere, CONTRACT_WITH_SLASHES, dotDelimitedName);
           
            reader.accept(ccv, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
           
            return ccv.isALookedForThing();
        }
        catch (IOException ioe) {
            nullCaches(dotDelimitedName);
           
            return false;
        }
        finally {
            if (is != null) {
                try {
                    is.close();
                }
                catch (IOException e) {
                    // Ignore
                }
            }
        }
    }
   
    /**
     * Returns true if the given class is a contract
     *
     * @param searchHere The file or jar to look in
     * @param dotDelimitedName The fully qualified class name to look for
     * @return The dot-delimited superclass name or null if this is terminal (is
     *   an interface or extends java.lang.Object)
     */
    private String getSuperclass(File searchHere, String dotDelimitedName) {
        if (FOUND_SUPERCLASS.containsKey(dotDelimitedName)) {
            return FOUND_SUPERCLASS.get(dotDelimitedName);
        }
       
        InputStream is = null;
        try {
            is = findClass(searchHere, dotDelimitedName, true, "superclass");
            if (is == null) {
                nullCaches(dotDelimitedName);
               
                return null;
            }
           
            ClassReader reader = new ClassReader(is);
           
            ContractClassVisitor ccv = new ContractClassVisitor(searchHere, null, dotDelimitedName);
           
            reader.accept(ccv, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
           
            return ccv.getDotDelimitedSuperclass();
        }
        catch (IOException ioe) {
            nullCaches(dotDelimitedName);
           
            return null;
        }
        finally {
            if (is != null) {
                try {
                    is.close();
                }
                catch (IOException e) {
                    // Ignore
                }
            }
        }
    }
   
    /**
     * Returns true if it can be determined that this class is a scope
     *
     * @param searchHere
     * @param dotDelimitedName
     * @return true if this class is a scope
     */
    public boolean isClassAScope(File searchHere, String dotDelimitedName) {
        if (ISA_SCOPE.containsKey(dotDelimitedName)) {
            return ISA_SCOPE.get(dotDelimitedName);
        }
       
        InputStream is = null;
        try {
            is = findClass(searchHere, dotDelimitedName, true, "isascope");
            if (is == null) {
                nullCaches(dotDelimitedName);
               
                return false;
            }
           
            ClassReader reader = new ClassReader(is);
           
            ContractClassVisitor ccv = new ContractClassVisitor(searchHere, SCOPE_WITH_SLASHES, dotDelimitedName);
           
            reader.accept(ccv, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
           
            return ccv.isALookedForThing();
        }
        catch (IOException ioe) {
            // Error on the side of not a contract
            nullCaches(dotDelimitedName);
           
            return false;
        }
        finally {
            if (is != null) {
                try {
                    is.close();
                }
                catch (IOException e) {
                    // Ignore
                }
            }
        }
    }
   
    /**
     * Returns true if it can be determined that this class is a qualifier
     *
     * @param searchHere
     * @param dotDelimitedName
     * @return true if this class is a qualifier
     */
    public boolean isClassAQualifier(File searchHere, String dotDelimitedName) {
        if (ISA_QUALIFIER.containsKey(dotDelimitedName)) {
            return ISA_QUALIFIER.get(dotDelimitedName);
        }
       
        InputStream is = null;
        try {
            is = findClass(searchHere, dotDelimitedName, true, "isaQualifier");
            if (is == null) {
                nullCaches(dotDelimitedName);
               
                return false;
            }
           
            ClassReader reader = new ClassReader(is);
           
            ContractClassVisitor ccv = new ContractClassVisitor(searchHere, QUALIFIER_WITH_SLASHES, dotDelimitedName);
           
            reader.accept(ccv, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
           
            return ccv.isALookedForThing();
        }
        catch (IOException ioe) {
            // Error on the side of not a contract
            nullCaches(dotDelimitedName);
           
            return false;
        }
        finally {
            if (is != null) {
                try {
                    is.close();
                }
                catch (IOException e) {
                    // Ignore
                }
            }
        }
    }
   
    /**
     * Returns true if it can be determined that this class is a generator
     *
     * @param searchHere
     * @param dotDelimitedName
     * @return true if this class is a qualifier
     */
    public GenerateMethodAnnotationData isClassAGenerator(File searchHere, String dotDelimitedName) {
        if (FOUND_GENERATORS.containsKey(dotDelimitedName)) {
            return FOUND_GENERATORS.get(dotDelimitedName);
        }
       
        InputStream is = null;
        try {
            is = findClass(searchHere, dotDelimitedName, true, "isaMethodGenerator");
            if (is == null) {
                nullCaches(dotDelimitedName);
               
                return null;
            }
           
            ClassReader reader = new ClassReader(is);
           
            GeneratorClassVisitor gcv = new GeneratorClassVisitor(dotDelimitedName);
           
            reader.accept(gcv, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
           
            return gcv.getGenerateMethodAnnotationData();
        }
        catch (IOException ioe) {
            // Error on the side of not a contract
            nullCaches(dotDelimitedName);
           
            return null;
        }
        finally {
            if (is != null) {
                try {
                    is.close();
                }
                catch (IOException e) {
                    // Ignore
                }
            }
        }
    }
   
    private void getAssociatedSuperclassContracts(File searchHere, String dotDelimitedName, Set<String> addToMe) {
        if (!addToMe.contains(dotDelimitedName) && isClassAContract(searchHere, dotDelimitedName)) {
            addToMe.add(dotDelimitedName);
        }
       
        String dotDelimitedSuperclass = getSuperclass(searchHere, dotDelimitedName);
        if (dotDelimitedSuperclass != null) {
            getAssociatedSuperclassContracts(searchHere, dotDelimitedSuperclass, addToMe);
        }
    }
   
    /**
     * Gets the contracts associated with the name passed in
     * @param searchHere
     * @param dotDelimitedName
     * @return The set of contracts associated with this dotDelimited name (ordered iterator)
     */
    public Set<String> getAssociatedContracts(File searchHere, String dotDelimitedName) {
        LinkedHashSet<String> retVal = new LinkedHashSet<String>();
        retVal.add(dotDelimitedName);
       
        getAssociatedSuperclassContracts(searchHere, dotDelimitedName, retVal);
       
        while (dotDelimitedName != null) {
            // getAssociatedSuperclassContracts is guaranteed to fill in the INTERFACES cache
            Set<String> allInterfaces = FOUND_INTERFACES.get(dotDelimitedName);
            if (allInterfaces == null) {
                dotDelimitedName = getSuperclass(searchHere, dotDelimitedName);
               
                continue;
            }
           
            for (String dotDelimitedInterface : allInterfaces) {
                if (isClassAContract(searchHere, dotDelimitedInterface)) {
                    retVal.add(dotDelimitedInterface)
                }
               
                addSubInterface(searchHere, dotDelimitedInterface, retVal);
            }
           
            dotDelimitedName = getSuperclass(searchHere, dotDelimitedName);
        }
       
        return retVal;
    }
   
    private void addSubInterface(File searchHere, String dotDelimitedInterface, LinkedHashSet<String> retVal) {
        Set<String> subInterfaces = FOUND_INTERFACES.get(dotDelimitedInterface);
        if (subInterfaces == null) return;
       
        for (String dotDelimitedSubInterface : subInterfaces) {
            if (isClassAContract(searchHere, dotDelimitedSubInterface)) {
                retVal.add(dotDelimitedSubInterface);
            }
           
            addSubInterface(searchHere, dotDelimitedSubInterface, retVal);
        }
    }
   
    private class ContractClassVisitor extends AbstractClassVisitorImpl {
        private final String cacheKey;
        private final String lookForMe;
        private final File searchHere;
       
        private final Map<String, String> methodNameToMetadataKey =
                new HashMap<String, String>();
       
        private boolean isLookedFor = false;
       
        private boolean isContract = false;
        private boolean isScope = false;
        private boolean isQualifier = false;
       
        private String dotDelimitedSuperclass;
       
        private ContractClassVisitor(File searchHere, String lookForMe, String cacheKey) {
            this.searchHere = searchHere;
            this.lookForMe = lookForMe;
            this.cacheKey = cacheKey;
        }
       
        /* (non-Javadoc)
         * @see org.objectweb.asm.ClassVisitor#visit(int, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
         */
        @Override
        public void visit(int version,
                int access,
                String name,
                String signature,
                String superName,
                String[] interfaces) {
            if (!FOUND_INTERFACES.containsKey(cacheKey)) {
                LinkedHashSet<String> iFaces = new LinkedHashSet<String>();
               
                for (String iFace : interfaces) {
                    String iWithDots = iFace.replace('/', '.');
                    iFaces.add(iWithDots);
                   
                    // Fill in the cache with all sub interfaces
                    getSuperclass(searchHere, iWithDots);
                }
               
                FOUND_INTERFACES.put(cacheKey, iFaces);
            }
           
            if (superName == null) {
                FOUND_SUPERCLASS.put(cacheKey, null);
               
                return;
            }
           
            dotDelimitedSuperclass = superName.replace('/', '.');
           
            if (Object.class.getName().equals(dotDelimitedSuperclass)) {
                dotDelimitedSuperclass = null;
            }
           
            FOUND_SUPERCLASS.put(cacheKey, dotDelimitedSuperclass);
        }
       
        /* (non-Javadoc)
         * @see org.objectweb.asm.ClassVisitor#visitAnnotation(java.lang.String, boolean)
         */
        @Override
        public AnnotationVisitor visitAnnotation(String desc, boolean arg1) {
            if (lookForMe != null && desc.equals(lookForMe)) {
                isLookedFor = true;
            }
           
            if (desc.equals(CONTRACT_WITH_SLASHES)) {
                isContract = true;
            }
           
            if (desc.equals(SCOPE_WITH_SLASHES)) {
                isScope = true;
            }
           
            if (desc.equals(QUALIFIER_WITH_SLASHES)) {
                isQualifier = true;
            }
           
            if (desc.equals(QUALIFIER_WITH_SLASHES)) {
                isQualifier = true;
            }
           
            return null;
        }
       
        /* (non-Javadoc)
         * @see org.objectweb.asm.ClassVisitor#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
         */
        @Override
        public MethodVisitor visitMethod(int arg0, String name, String arg2,
                String arg3, String[] arg4) {
            return new ContractMethodVisitor(this, name);
        }
       
        public void visitEnd() {
            ISA_CONTRACT.put(cacheKey, isContract);
            ISA_SCOPE.put(cacheKey, isScope);
            ISA_QUALIFIER.put(cacheKey, isQualifier);
           
            if ((isScope || isQualifier) && !methodNameToMetadataKey.isEmpty()) {
                METADATA.put(cacheKey, methodNameToMetadataKey);
            }
        }
       
        private boolean isALookedForThing() {
            return isLookedFor;
        }
       
        private String getDotDelimitedSuperclass() {
            return dotDelimitedSuperclass;
        }
       
        private void associateMethodNameWithMetadataKey(
                String methodName,
                String metadataKey) {
            methodNameToMetadataKey.put(methodName, metadataKey);
        }
       
    }
   
    private static class ContractMethodVisitor extends AbstractMethodVisitorImpl {
        private final ContractClassVisitor parent;
        private final String methodName;
        private String metadataKey;
       
        private ContractMethodVisitor(ContractClassVisitor parent, String methodName) {
            this.parent = parent;
            this.methodName = methodName;
        }

        /* (non-Javadoc)
         * @see org.objectweb.asm.MethodVisitor#visitAnnotation(java.lang.String, boolean)
         */
        @Override
        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
            if (!METADATA_DESC.equals(desc)) return null;
           
            return new MetadataAnnotationVisitor(this);
        }

        /* (non-Javadoc)
         * @see org.objectweb.asm.MethodVisitor#visitEnd()
         */
        @Override
        public void visitEnd() {
            if (metadataKey != null) {
                parent.associateMethodNameWithMetadataKey(methodName, metadataKey);
            }
           
        }
       
        private void setMetadataKey(String key) {
            metadataKey = key;
        }
    }
   
    private static class MetadataAnnotationVisitor extends AbstractAnnotationVisitorImpl {
        private final ContractMethodVisitor parent;
       
        private MetadataAnnotationVisitor(ContractMethodVisitor parent) {
            this.parent = parent;
        }
       
        /* (non-Javadoc)
         * @see org.objectweb.asm.AnnotationVisitor#visitAnnotation(java.lang.String, java.lang.String)
         */
        @Override
        public void visit(String name, Object value) {
            parent.setMetadataKey((String) value);
        }
    }
   
    private class GeneratorClassVisitor extends AbstractClassVisitorImpl {
        private final String cacheKey;
        private GenerateMethodAnnotationData methodGenerateData = null;
       
        private GeneratorClassVisitor(String cacheKey) {
            this.cacheKey = cacheKey;
        }
       
        /* (non-Javadoc)
         * @see org.objectweb.asm.ClassVisitor#visitAnnotation(java.lang.String, boolean)
         */
        @Override
        public AnnotationVisitor visitAnnotation(String desc, boolean arg1) {
            if (desc.equals(METHOD_GENERATOR_WITH_SLASHES)) {
                return new GenerateServiceFromMethodVisitor(this);
            }
           
            return null;
        }
       
        /* (non-Javadoc)
         * @see org.objectweb.asm.ClassVisitor#visitMethod(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String[])
         */
        @Override
        public MethodVisitor visitMethod(int access,
                String name,
                String desc,
                String signature,
                String[] exceptions) {
            if (methodGenerateData == null) {
                return null;
            }
           
            return new GeneratorNameFinderMethodVisitor(this, name);
        }
       
        private void setGenerateMethodAnnotationData(GenerateMethodAnnotationData methodGenerateData) {
            this.methodGenerateData = methodGenerateData;
           
        }
       
        private GenerateMethodAnnotationData getGenerateMethodAnnotationData() {
            return methodGenerateData;
        }
       
        private void setNameMethodName(String methodName) {
            methodGenerateData.setNameMethodName(methodName);
        }
       
        /* (non-Javadoc)
         * @see org.objectweb.asm.ClassVisitor#visitEnd()
         */
        @Override
        public void visitEnd() {
            FOUND_GENERATORS.put(cacheKey, methodGenerateData);
        }
    }
   
    private final static String GENERATOR_IMPL_NAME = "implementation";
    private final static String GENERATOR_SCOPE_NAME = "scope";
   
    private static class GenerateServiceFromMethodVisitor extends AbstractAnnotationVisitorImpl {
        private final GeneratorClassVisitor parent;
       
        private String implementation;
        private String scope = PerLookup.class.getName();
        private final HashSet<String> contracts = new HashSet<String>();
       
        private GenerateServiceFromMethodVisitor(GeneratorClassVisitor parent) {
            this.parent = parent;
        }
       
        /* (non-Javadoc)
         * @see org.objectweb.asm.AnnotationVisitor#visitAnnotation(java.lang.String, java.lang.String)
         */
        @Override
        public void visit(String name, Object value) {
            if (name == null) {
                // This is the contracts array
                contracts.add((String) value);
            }
            else if (GENERATOR_IMPL_NAME.equals(name)) {
                implementation = (String) value;
            }
            else if (GENERATOR_SCOPE_NAME.equals(name)) {
                scope = (String) value;
            }
        }
       
        /* (non-Javadoc)
         * @see org.objectweb.asm.AnnotationVisitor#visitArray(java.lang.String)
         */
        @Override
        public AnnotationVisitor visitArray(String name) {
            return this;
        }
       
        /* (non-Javadoc)
         * @see org.objectweb.asm.AnnotationVisitor#visitEnd()
         */
        @Override
        public void visitEnd() {
            parent.setGenerateMethodAnnotationData(
                    new GenerateMethodAnnotationData(implementation, contracts, scope));
        }
       
    }
   
    private static class GeneratorNameFinderMethodVisitor extends AbstractMethodVisitorImpl {
        private final String methodName;
        private final GeneratorClassVisitor parent;
       
        private GeneratorNameFinderMethodVisitor(GeneratorClassVisitor parent, String methodName) {
            this.parent = parent;
            this.methodName = methodName;
        }

        /* (non-Javadoc)
         * @see org.objectweb.asm.MethodVisitor#visitAnnotation(java.lang.String, boolean)
         */
        @Override
        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
            if (GENERATOR_NAME_FIELD_WITH_SLASHES.equals(desc)) {
                parent.setNameMethodName(methodName);
               
            }
           
            return null;
        }

        /* (non-Javadoc)
         * @see org.objectweb.asm.MethodVisitor#visitEnd()
         */
        @Override
        public void visitEnd() {
            // TODO Auto-generated method stub
           
        }
       
    }
   
    private static class KnownClassData {
        private final String clazz;
        private final boolean isa_contract;
        private final boolean isa_scope;
        private final boolean isa_qualifier;
        private final String superclass;
        private final Set<String> iFaces;
       
        private KnownClassData(String clazz,
                boolean isa_contract,
                boolean isa_scope,
                boolean isa_qualifier,
                String superclass,
                Set<String> iFaces) {
            this.clazz = clazz;
            this.isa_contract = isa_contract;
            this.isa_scope = isa_scope;
            this.isa_qualifier = isa_qualifier;
            this.superclass = superclass;
            this.iFaces = iFaces;
        }

        /**
         * @return the clazz
         */
        String getClazz() {
            return clazz;
        }

        /**
         * @return the isa_contract
         */
        boolean isIsa_contract() {
            return isa_contract;
        }

        /**
         * @return the isa_scope
         */
        boolean isIsa_scope() {
            return isa_scope;
        }

        /**
         * @return the isa_qualifier
         */
        boolean isIsa_qualifier() {
            return isa_qualifier;
        }

        /**
         * @return the superclass
         */
        String getSuperclass() {
            return superclass;
        }

        /**
         * @return the iFaces
         */
        Set<String> getiFaces() {
            return iFaces;
        }
    }
   
    public String getMetadataKey(String scopeOrQualifier, String methodName) {
        Map<String, String> methodToKey = METADATA.get(scopeOrQualifier);
        if (methodToKey == null) return null;
       
        return methodToKey.get(methodName);
    }
   
    private final static String LIST_WITH_PTYPE = "Ljava/util/List<";
   
    /* package */ static String getListActualType(String signature) {
        if (signature == null) return null;
        if (!signature.contains(LIST_WITH_PTYPE)) return null;
       
        int ltIndex = signature.indexOf('<');
        int gtIndex = signature.indexOf('>');
       
        if (ltIndex < 0 || gtIndex < 0) return null;
       
        String pType = signature.substring(ltIndex + 1, gtIndex);
        if (!pType.startsWith("L")) return null;
       
        pType = pType.substring(1, pType.length() - 1)// Remove L and ;
       
        return pType.replace('/', '.');
    }
   
    /* package */ static String getFirstParameterType(String desc) {
        if (desc == null) return null;
        if (!desc.startsWith("(L")) return null;
        int semiColonIndex = desc.indexOf(';');
        if (semiColonIndex < 0) return null// Badly formed desc?
       
        String postL = desc.substring(2, semiColonIndex);
       
        return postL.replace('/', '.');
    }
}
TOP

Related Classes of org.jvnet.hk2.generator.internal.Utilities$GenerateServiceFromMethodVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.