FELIX-3332 : SCR annotations @Activate @Deactivate @Modified in outer classes also affect nested classes, annotations in nested classes are ignored 

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1440660 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/helper/ClassScanner.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/helper/ClassScanner.java
index 195f45c..4217a2b 100644
--- a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/helper/ClassScanner.java
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/helper/ClassScanner.java
@@ -143,26 +143,7 @@
                 // load the class
                 final Class<?> annotatedClass = project.getClassLoader().loadClass(src.getClassName());
 
-                final ClassDescription desc = this.processClass(annotatedClass, src.getFile().toString());
-                if ( desc != null ) {
-                    this.allDescriptions.put(annotatedClass.getName(), desc);
-                    if ( desc.getDescriptions(ComponentDescription.class).size() > 0) {
-                        result.add(desc);
-                        log.debug("Found component description " + desc + " in " + annotatedClass.getName());
-                    } else {
-                        // check whether one of the other annotations is used and log a warning (FELIX-3636)
-                        if ( desc.getDescription(PropertyDescription.class) != null
-                             || desc.getDescription(ReferenceDescription.class) != null
-                             || desc.getDescription(ServiceDescription.class) != null ) {
-                            iLog.addWarning("Class '" + src.getClassName() + "' contains SCR annotations, but not a" +
-                                 "@Component (or equivalent) annotation. Therefore no component descriptor is created for this" +
-                                 "class. Please add a @Component annotation and consider making it abstract.",
-                                 src.getFile().toString());
-                        }
-                    }
-                } else {
-                    this.allDescriptions.put(annotatedClass.getName(), new ClassDescription(annotatedClass, GENERATED));
-                }
+                this.process(annotatedClass, src, result);
             } catch (final ClassNotFoundException cnfe) {
                 throw new SCRDescriptorFailureException("Unable to load compiled class: " + src.getClassName(), cnfe);
             }
@@ -171,6 +152,41 @@
     }
 
     /**
+     * Process a class
+     * @throws SCRDescriptorException
+     * @throws SCRDescriptorFailureException
+     */
+    private void process(final Class<?> annotatedClass, final Source src, final List<ClassDescription> result)
+    throws SCRDescriptorFailureException, SCRDescriptorException {
+        final ClassDescription desc = this.processClass(annotatedClass, src.getFile().toString());
+        if ( desc != null ) {
+            this.allDescriptions.put(annotatedClass.getName(), desc);
+            if ( desc.getDescriptions(ComponentDescription.class).size() > 0) {
+                result.add(desc);
+                log.debug("Found component description " + desc + " in " + annotatedClass.getName());
+            } else {
+                // check whether one of the other annotations is used and log a warning (FELIX-3636)
+                if ( desc.getDescription(PropertyDescription.class) != null
+                     || desc.getDescription(ReferenceDescription.class) != null
+                     || desc.getDescription(ServiceDescription.class) != null ) {
+                    iLog.addWarning("Class '" + src.getClassName() + "' contains SCR annotations, but not a" +
+                         "@Component (or equivalent) annotation. Therefore no component descriptor is created for this" +
+                         "class. Please add a @Component annotation and consider making it abstract.",
+                         src.getFile().toString());
+                }
+            }
+        } else {
+            this.allDescriptions.put(annotatedClass.getName(), new ClassDescription(annotatedClass, GENERATED));
+        }
+        // process inner classes
+        for(final Class<?> innerClass : annotatedClass.getDeclaredClasses()) {
+            if ( !innerClass.isAnnotation() && !innerClass.isInterface() ) {
+                process(innerClass, src, result);
+            }
+        }
+    }
+
+    /**
      * Scan a single class.
      */
     private ClassDescription processClass(final Class<?> annotatedClass, final String location)
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/xml/ComponentDescriptorIO.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/xml/ComponentDescriptorIO.java
index 0f2eb45..2836783 100644
--- a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/xml/ComponentDescriptorIO.java
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/xml/ComponentDescriptorIO.java
@@ -24,7 +24,7 @@
 import java.io.InputStream;
 import java.security.Provider.Service;
 import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 import java.util.StringTokenizer;
 
@@ -765,11 +765,34 @@
         final List<String> fileNames = new ArrayList<String>();
         if ( options.isGenerateSeparateDescriptors() ) {
             final SpecVersion globalVersion = module.getOptions().getSpecVersion();
-            for(final ComponentContainer component : components ) {
+            while ( !components.isEmpty() ) {
+                // get the first component
+                final List<ComponentContainer> innerList = new ArrayList<ComponentContainer>();
+                final ComponentContainer component = components.remove(0);
+                innerList.add(component);
+                final int pos = component.getClassDescription().getDescribedClass().getName().indexOf('$');
+                final String baseClassName;
+                if ( pos == -1 ) {
+                    baseClassName = component.getClassDescription().getDescribedClass().getName();
+                } else {
+                    baseClassName = component.getClassDescription().getDescribedClass().getName().substring(0, pos);
+                }
+                final String baseClassPrefix = baseClassName + '$';
+
+                // check for inner classes
+                final Iterator<ComponentContainer> i = components.iterator();
+                while ( i.hasNext() ) {
+                    final ComponentContainer cc = i.next();
+                    if ( cc.getClassDescription().getDescribedClass().getName().startsWith(baseClassPrefix) ) {
+                        innerList.add(cc);
+                        i.remove();
+                    }
+                }
+
                 module.getOptions().setSpecVersion(component.getComponentDescription().getSpecVersion());
-                final File file = new File(descriptorDir, component.getClassDescription().getDescribedClass().getName() + ".xml");
+                final File file = new File(descriptorDir, baseClassName + ".xml");
                 try {
-                    ComponentDescriptorIO.generateXML(module, Collections.singletonList(component), file, logger);
+                    ComponentDescriptorIO.generateXML(module, innerList, file, logger);
                 } catch (final IOException e) {
                     throw new SCRDescriptorException("Unable to generate xml", file.toString(), e);
                 } catch (final TransformerException e) {
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/xml/MetaTypeIO.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/xml/MetaTypeIO.java
index 208bb79..7aa1dfb 100644
--- a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/xml/MetaTypeIO.java
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/xml/MetaTypeIO.java
@@ -21,7 +21,6 @@
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -97,14 +96,43 @@
 
                 final List<String> fileNames = new ArrayList<String>();
                 if ( options.isGenerateSeparateDescriptors() ) {
+                    // create a list with relevant components
+                    final List<ComponentContainer> components = new ArrayList<ComponentContainer>();
                     for(final ComponentContainer component : module.getComponents() ) {
                         if ( component.getMetatypeContainer() != null ) {
-                            final File file = new File(mtDir, component.getClassDescription().getDescribedClass().getName() + ".xml");
-                            logger.info("Generating 1 MetaType Descriptor in " + file);
-                            MetaTypeIO.write(module, Collections.singletonList(component), file);
-                            fileNames.add(parentDir.getName() + '/' + mtDir.getName() + '/' + file.getName());
+                            components.add(component);
                         }
                     }
+
+                    while ( !components.isEmpty() ) {
+                        // get the first component
+                        final List<ComponentContainer> innerList = new ArrayList<ComponentContainer>();
+                        final ComponentContainer component = components.remove(0);
+                        innerList.add(component);
+                        final int pos = component.getClassDescription().getDescribedClass().getName().indexOf('$');
+                        final String baseClassName;
+                        if ( pos == -1 ) {
+                            baseClassName = component.getClassDescription().getDescribedClass().getName();
+                        } else {
+                            baseClassName = component.getClassDescription().getDescribedClass().getName().substring(0, pos);
+                        }
+                        final String baseClassPrefix = baseClassName + '$';
+
+                        // check for inner classes
+                        final Iterator<ComponentContainer> i = components.iterator();
+                        while ( i.hasNext() ) {
+                            final ComponentContainer cc = i.next();
+                            if ( cc.getClassDescription().getDescribedClass().getName().startsWith(baseClassPrefix) ) {
+                                innerList.add(cc);
+                                i.remove();
+                            }
+                        }
+
+                        final File file = new File(mtDir, baseClassName + ".xml");
+                        logger.info("Generating " + innerList.size() + " MetaType Descriptor in " + file);
+                        MetaTypeIO.write(module, innerList, file);
+                        fileNames.add(parentDir.getName() + '/' + mtDir.getName() + '/' + file.getName());
+                    }
                 } else {
                     logger.info("Generating " + metatypeCount + " MetaType Descriptors in " + mtFile);
                     MetaTypeIO.write(module, module.getComponents(), mtFile);