Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
  */
 package org.apache.felix.scrplugin.helper;
 
 import static org.objectweb.asm.ClassReader.SKIP_CODE;
 import static org.objectweb.asm.ClassReader.SKIP_DEBUG;
 import static org.objectweb.asm.ClassReader.SKIP_FRAMES;
 
 import java.io.File;
 import java.util.List;
 import java.util.Map;
 
The class scanner scans class files for annotations and invokes the org.apache.felix.scrplugin.annotations.AnnotationProcessor on each scanned class file.
 
 public class ClassScanner {

    
The name of the Bundle manifest header providing the list of service component descriptor files.
 
     private static final String SERVICE_COMPONENT = "Service-Component";

    
The name of the file containing the scanned information from older SCR generator versions.
 
     private static final String ABSTRACT_DESCRIPTOR_ARCHIV_PATH = "OSGI-INF/scr-plugin/scrinfo.xml";

    
Source for all generated descriptions.
 
     private static final String GENERATED = "<generated>";

    
With this syntax array pameters names are returned by reflection API
 
     private static final Pattern ARRAY_PARAM_TYPE_NAME = Pattern.compile("^\\[L(.*);$");

    
Component descriptions loaded from dependencie
 
     private Map<StringClassDescriptionloadedDependencies;

    
All used component descriptions.
 
     private final Map<StringClassDescriptionallDescriptions;

    
The log.
 
     private final Log log;

    
The issue log.
    private final IssueLog iLog;

    
The project.
    private final Project project;

    
The annotation processor.
    private final AnnotationProcessor aProcessor;

    
Create a new scanner.
    public ClassScanner(final Log log,
            final IssueLog iLog,
            final Project project,
            final AnnotationProcessor aProcessor) {
        // create map for all descriptions and dummy entry for Object
        this. = new HashMap<StringClassDescription>();
        .put(Object.class.getName(), new ClassDescription(Object.class));
        this. = log;
        this. = iLog;
        this. = project;
        this. = aProcessor;
    }

    
Scan all source class files for annotations and process them.
            throws SCRDescriptorExceptionSCRDescriptorFailureException {
        final List<ClassDescriptionresult = new ArrayList<ClassDescription>();
        for (final Source src : .getSources()) {
            if ( src.getFile().getName().equals("package-info.java") ) {
                .debug("Skipping file " + src.getClassName());
                continue;
            }
            .debug("Scanning class " + src.getClassName());
            try {
                // load the class
                final Class<?> annotatedClass = .getClassLoader().loadClass(src.getClassName());
                final ClassDescription desc = this.processClass(annotatedClasssrc.getFile().toString());
                if ( desc != null ) {
                    this..put(annotatedClass.getName(), desc);
                    if ( desc.getDescriptions(ComponentDescription.class).size() > 0) {
                        result.add(desc);
                        .debug("Found component description " + desc + " in " + annotatedClass.getName());
                    }
                } else {
                    this..put(annotatedClass.getName(), new ClassDescription(annotatedClass));
                }
            } catch (final ClassNotFoundException cnfe) {
                throw new SCRDescriptorFailureException("Unable to load compiled class: " + src.getClassName(), cnfe);
            }
        }
        return result;
    }

    
Scan a single class.
    private ClassDescription processClass(final Class<?> annotatedClassfinal String location)
            throws SCRDescriptorFailureExceptionSCRDescriptorException {
        .debug("Processing " + annotatedClass.getName());
        try {
            // get the class file for ASM
            final String pathToClassFile = annotatedClass.getName().replace('.''/') + ".class";
            final InputStream input = .getClassLoader().getResourceAsStream(pathToClassFile);
            final ClassReader classReader;
            try {
                classReader = new ClassReader(input);
            } finally {
                input.close();
            }
            final ClassNode classNode = new ClassNode();
            classReader.accept(classNode |  | );
            // create descriptions
            final List<ScannedAnnotationannotations = extractAnnotation(classNodeannotatedClass);
            if (annotations.size() > 0) {
                // process annotations and create descriptions
                final ClassDescription desc = new ClassDescription(annotatedClasslocation);
                .process(new ScannedClass(annotationsannotatedClass), desc);
                .debug("Found descriptions " + desc + " in " + annotatedClass.getName());
                return desc;
            }
        } catch (final IOException ioe) {
            throw new SCRDescriptorFailureException("Unable to scan class files: " + annotatedClass.getName(), ioe);
        }
        return null;
    }

    
Extract annotations
    private final List<ScannedAnnotationextractAnnotation(final ClassNode classNodefinal Class<?> annotatedClass)
            throws SCRDescriptorException {
        final List<ScannedAnnotationdescriptions = new ArrayList<ScannedAnnotation>();
        // first parse class annotations
        @SuppressWarnings("unchecked")
        final List<AnnotationNodeannotations = getAllAnnotations(classNode.invisibleAnnotationsclassNode.visibleAnnotations);
        if (annotations != null) {
            for (final AnnotationNode annotation : annotations) {
                this.parseAnnotation(descriptionsannotationannotatedClass);
            }
            // second parse method annotations
            @SuppressWarnings("unchecked")
            final List<MethodNodemethods = classNode.methods;
            if (methods != null) {
                for (final MethodNode method : methods) {
                    final String name = method.name;
                    // check for constructor
                    if ( !"<init>".equals(name) ) {
                        @SuppressWarnings("unchecked")
                        final List<AnnotationNodeannos = getAllAnnotations(method.invisibleAnnotationsmethod.visibleAnnotations);
                        if (annos != null) {
                            final Type[] signature = Type.getArgumentTypes(method.desc);
                            final Method[] allMethods = annotatedClass.getDeclaredMethods();
                            Method found = null;
                            for (final Method m : allMethods) {
                                if (m.getName().equals(name)) {
                                    if (m.getParameterTypes().length == 0 && (signature == null || signature.length == 0) ) {
                                        found = m;
                                    }
                                    if (m.getParameterTypes().length > 0 && signature != null && m.getParameterTypes().length == signature.length) {
                                        found = m;
                                        for(int index = 0; index < m.getParameterTypes().lengthindex++ ) {
                                            String parameterTypeName = m.getParameterTypes()[index].getName();
                                            // Name of array parameters is returned with syntax [L<name>;, convert to <name>[]
                                            Matcher matcher = .matcher(parameterTypeName);
                                            if (matcher.matches()) {
                                                parameterTypeName = matcher.group(1) + "[]";
                                            }
                                            if (!parameterTypeName.equals(signature[index].getClassName()) &&
                                                    !m.getParameterTypes()[index].getSimpleName().equals(signature[index].getClassName())) {
                                                found = null;
                                            }
                                        }
                                    }
                                    // if method is found return it now, to avoid resetting 'found' to null if next method has same name but different parameters
                                    if (found != null) {
                                        break;
                                    }
                                }
                            }
                            if (found == null) {
                                throw new SCRDescriptorException("Annotated method " + name + " not found.",
                                        annotatedClass.getName());
                            }
                            for (final AnnotationNode annotation : annos) {
                                parseAnnotation(descriptionsannotationfound);
                            }
                        }
                    }
                }
            }
            // third parse field annotations
            @SuppressWarnings("unchecked")
            final List<FieldNodefields = classNode.fields;
            if (fields != null) {
                for (final FieldNode field : fields) {
                    @SuppressWarnings("unchecked")
                    final List<AnnotationNodeannos = getAllAnnotations(field.invisibleAnnotationsfield.visibleAnnotations);
                    if (annos != null) {
                        final String name = field.name;
                        final Field[] allFields = annotatedClass.getDeclaredFields();
                        Field found = null;
                        for (final Field f : allFields) {
                            if (f.getName().equals(name)) {
                                found = f;
                                break;
                            }
                        }
                        if (found == null) {
                            throw new SCRDescriptorException("Annotated field " + name + " not found.",
                                    annotatedClass.getName());
                        }
                        for (final AnnotationNode annotation : annos) {
                            parseAnnotation(descriptionsannotationfound);
                        }
                    }
                }
            }
        }
        return descriptions;
    }

    
Method is used to get both invisible (e.g. RetentionPolicy.CLASS) and visible (e.g. RetentionPolicy.RUNTIME) annotations. Although it is recommended to use RetentionPolicy.CLASS for SCR annotations, it may make sense to declae them with another RetentionPolicy if the same annotation is used for other usecases which require runtime access as well.

Parameters:
annotationLists List of invisible and visible annotations.
Returns:
List with all annotations from all lists, or null if none found
    private List<AnnotationNodegetAllAnnotations(List<AnnotationNode>... annotationLists) {
        List<AnnotationNoderesultList = null;
        for (List<AnnotationNodeannotationList : annotationLists) {
            if (annotationList!=null && annotationList.size()>0) {
                if (resultList==null) {
                    resultList = new ArrayList<AnnotationNode>();
                }
                resultList.addAll(annotationList);
            }
        }
        return resultList;
    }
    private <T> T[] convertToArray(final List<?> valuesfinal Class<T> type) {
        @SuppressWarnings("unchecked")
        final T[] result = (T[]) Array.newInstance(typevalues.size());
        return values.toArray(result);
    }

    
Parse annotation and create a description.
    private void parseAnnotation(final List<ScannedAnnotationdescriptionsfinal AnnotationNode annotation,
            final Object annotatedObject) {
        // desc has the format 'L' + className.replace('.', '/') + ';'
        final String name = annotation.desc.substring(1, annotation.desc.length() - 1).replace('/''.');
        Map<StringObjectvalues = null;
        if (annotation.values != null) {
            values = new HashMap<StringObject>();
            final Iterator<?> i = annotation.values.iterator();
            while (i.hasNext()) {
                final Object vName = i.next();
                Object value = i.next();
                // convert type to class name string
                if (value instanceof Type) {
                    value = ((Typevalue).getClassName();
                } else if (value instanceof List<?>) {
                    final List<?> objects = (List<?>) value;
                    if (objects.size() > 0) {
                        if (objects.get(0) instanceof Type) {
                            final String[] classNames = new String[objects.size()];
                            int index = 0;
                            for (final Object v : objects) {
                                classNames[index] = ((Typev).getClassName();
                                index++;
                            }
                            value = classNames;
                        } else if (objects.get(0) instanceof AnnotationNode) {
                            final List<ScannedAnnotationinnerDesc = new ArrayList<ScannedAnnotation>();
                            for (final Object v : objects) {
                                parseAnnotation(innerDesc, (AnnotationNodevannotatedObject);
                            }
                            if (annotatedObject instanceof Method) {
                                value = innerDesc.toArray(new MethodAnnotation[innerDesc.size()]);
                            } else if (annotatedObject instanceof Field) {
                                value = innerDesc.toArray(new FieldAnnotation[innerDesc.size()]);
                            } else {
                                value = innerDesc.toArray(new ClassAnnotation[innerDesc.size()]);
                            }
                        } else {
                            value = convertToArray(objectsobjects.get(0).getClass());
                        }
                    } else {
                        value = null;
                    }
                }
                values.put(vName.toString(), value);
            }
        }
        final ScannedAnnotation a;
        if (annotatedObject instanceof Method) {
            a = new MethodAnnotation(namevalues, (MethodannotatedObject);
            ((MethodannotatedObject).setAccessible(true);
        } else if (annotatedObject instanceof Field) {
            a = new FieldAnnotation(namevalues, (FieldannotatedObject);
            ((FieldannotatedObject).setAccessible(true);
        } else {
            a = new ClassAnnotation(namevalues);
        }
        descriptions.add(a);
    }

    
Get a description for the class
    public ClassDescription getDescription(final Class<?> clazz)
            throws SCRDescriptorExceptionSCRDescriptorFailureException {
        final String name = clazz.getName();
        ClassDescription result = this..get(name);
        if ( result == null ) {
            // use scanner first
            result = this.processClass(clazz);
            if ( result == null ) {
                // now check loaded dependencies
                result = this.getComponentDescriptors().get(name);
            }
            // not found, create dummy
            if ( result == null ) {
                result = new ClassDescription(clazz);
            }
            // and cache
            .put(nameresult);
        }
        return result.clone();
    }

    
Returns a map of component descriptors which may be extended by the java sources.

This method calls the getDependencies() method and checks for any Service-Component descriptors in the returned files.

This method may be overwritten by extensions of this class.

Throws:
org.apache.felix.scrplugin.SCRDescriptorException May be thrown if an error occurs gathering the component descriptors.
            throws SCRDescriptorException {
        if (  == null ) {
             = new HashMap<StringClassDescription>();
            final Collection<Filedependencies = this..getDependencies();
            for ( final File artifact : dependencies ) {
                try {
                    this..debug"Trying to get scrinfo from artifact " + artifact );
                    // First try to read the private scr info file from previous scr generator versions
                    InputStream scrInfoFile = null;
                    try {
                        scrInfoFile = this.getFileartifact );
                        if ( scrInfoFile != null ) {
                            this.readServiceComponentDescriptorscrInfoFileartifact.toString() + ':' + );
                            continue;
                        }
                        this..debug"Artifact has no scrinfo file (it's optional): " + artifact );
                    } catch ( final IOException ioe ) {
                        throw new SCRDescriptorException"Unable to get scrinfo from artifact"artifact.toString(),
                                ioe );
                    } finally {
                        if ( scrInfoFile != null ) {
                            try { scrInfoFile.close(); } catch ( final IOException ignore ) {}
                        }
                    }
                    this..debug"Trying to get manifest from artifact " + artifact );
                    final Manifest manifest = this.getManifestartifact );
                    if ( manifest != null ) {
                        // read Service-Component entry
                        if ( manifest.getMainAttributes().getValue ) != null ) {
                            final String serviceComponent = manifest.getMainAttributes().getValue( );
                            this..debug"Found Service-Component: " + serviceComponent + " in artifact " + artifact );
                            final StringTokenizer st = new StringTokenizerserviceComponent"," );
                            while ( st.hasMoreTokens() ) {
                                final String entry = st.nextToken().trim();
                                if ( entry.length() > 0 ) {
                                    this.readServiceComponentDescriptorartifactentry );
                                }
                            }
                        } else {
                            this..debug"Artifact has no service component entry in manifest " + artifact );
                        }
                    } else {
                        this..debug"Unable to get manifest from artifact " + artifact );
                    }
                } catch ( IOException ioe ) {
                    throw new SCRDescriptorException"Unable to get manifest from artifact"artifact.toString(),
                            ioe );
                }
            }
        }
        return this.;
    }

    
Parses the descriptors read from the given input stream. This method may be called by the getComponentDescriptors() method to parse the descriptors gathered in an implementation dependent way.

Throws:
org.apache.felix.scrplugin.SCRDescriptorException If an error occurs reading the descriptors from the stream.
    private void readServiceComponentDescriptor(
            final InputStream filefinal String location )
                    throws SCRDescriptorException {
        final List<ClassDescriptionlist = ComponentDescriptorIO.readfilethis..getClassLoader(), location );
        if ( list != null ) {
            for(final ClassDescription cd : list) {
                final String name;
                if ( cd.getDescribedClass() == null ) {
                    name = cd.getDescription(ComponentDescription.class).getName();
                } else {
                    name = cd.getDescribedClass().getName();
                }
                .put(namecd);
            }
        }
    }

    
Read the service component description.

    private void readServiceComponentDescriptorfinal File artifactFileString entry ) {
        this..debug"Reading " + entry + " from " + artifactFile );
        InputStream xml = null;
        try {
            xml = this.getFileartifactFileentry );
            if ( xml == null ) {
                throw new SCRDescriptorException"Entry " + entry + " not contained in JAR File "artifactFile.toString());
            }
            this.readServiceComponentDescriptorxmlartifactFile.toString() + ':' + entry );
        } catch ( final IOException mee ) {
            this..warn"Unable to read SCR descriptor file from JAR File " + artifactFile + " at " + entry );
            this..debug"Exception occurred during reading: " + mee.getMessage(), mee );
        } catch ( final SCRDescriptorException mee ) {
            this..warn"Unable to read SCR descriptor file from JAR File " + artifactFile + " at " + entry );
            this..debug"Exception occurred during reading: " + mee.getMessage(), mee );
        } finally {
            if ( xml != null ) {
                try { xml.close(); } catch (final IOException ignore) {}
            }
        }
    }


    
Get the manifest from the artifact. The artifact can either be a jar or a directory.
    private Manifest getManifestfinal File artifact ) throws IOException {
        if ( artifact.isDirectory() ) {
            // this is maybe a classes directory, try to read manifest file directly
            final File dir = new File(artifact"META-INF");
            if ( !dir.exists() || !dir.isDirectory() ) {
                return null;
            }
            final File mf = new File(dir"MANIFEST.MF");
            if ( !mf.exists() || !mf.isFile() ) {
                return null;
            }
            final InputStream is = new FileInputStream(mf);
            try {
                return new Manifest(is);
            } finally {
                try { is.close(); } catch (final IOException ignore) { }
            }
        }
        JarFile file = null;
        try {
            file = new JarFileartifact );
            return file.getManifest();
        } finally {
            if ( file != null ) {
                try { file.close(); } catch ( final IOException ignore ) {}
            }
        }
    }
    private InputStream getFilefinal File artifactFilefinal String path ) throws IOException {
        if ( artifactFile.isDirectory() ) {
            final String filePath = path.replace('/'.).replace('\\'.);
            final File file = new File(artifactFilefilePath);
            if ( file.exists() && file.isFile() ) {
                return new FileInputStream(file);
            }
            return null;
        }
        JarFile file = null;
        try {
            file = new JarFileartifactFile );
            final JarEntry entry = file.getJarEntrypath );
            if ( entry != null ) {
                final InputStream stream = new ArtifactFileInputStreamfileentry );
                file = null// prevent file from being closed now
                return stream;
            }
            return null;
        } finally {
            if ( file != null ) {
                try { file.close(); } catch ( final IOException ignore ) {}
            }
        }
    }
    private static class ArtifactFileInputStream extends FilterInputStream {
        final JarFile jarFile;
        ArtifactFileInputStreamJarFile jarFileJarEntry jarEntry ) throws IOException {
            superjarFile.getInputStreamjarEntry ) );
            this. = jarFile;
        }
        @Override
        public void close() throws IOException {
            try {
                super.close();
            } catch ( final IOException ioe ) {
                // ignore
            }
            .close();
        }
        @Override
        protected void finalize() throws Throwable {
            try {
                close();
            } finally {
                super.finalize();
            }
        }
    }
New to GrepCode? Check out our FAQ X