FELIX-3550 : Reimplement the SCR Generator

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1354936 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/SCRDescriptorGenerator.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/SCRDescriptorGenerator.java
index 317c129..ed07973 100644
--- a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/SCRDescriptorGenerator.java
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/SCRDescriptorGenerator.java
@@ -190,23 +190,19 @@
         this.logger.debug("Generating descriptor for spec version: " + specVersion);
         options.setSpecVersion(specVersion);
 
-        // now check for abstract components and fill components objects
         final DescriptionContainer module = new DescriptionContainer(this.options);
 
-        for (final ComponentContainer container : processedContainers) {
-            final int errorCount = iLog.getNumberOfErrors();
+        // before we can validate we should check the references for bind/unbind method
+        // in order to create them if possible
+        if ( this.options.isGenerateAccessors() ) {
 
-            final Validator validator = new Validator(container, project, options, iLog);
-
-            if ( this.options.isGenerateAccessors() ) {
-                // before we can validate we should check the references for bind/unbind method
-                // in order to create them if possible
-
+            for (final ComponentContainer container : processedContainers) {
                 for (final ReferenceDescription ref : container.getReferences().values()) {
                     // if this is a field with a single cardinality,
                     // we look for the bind/unbind methods
                     // and create them if they are not availabe
                     if (ref.getStrategy() != ReferenceStrategy.LOOKUP && ref.getField() != null
+                        && ref.getField().getClass().getName().equals(container.getClassDescription().getDescribedClass().getName())
                         && (ref.getCardinality() == ReferenceCardinality.OPTIONAL_UNARY || ref.getCardinality() == ReferenceCardinality.MANDATORY_UNARY)) {
 
                         final String bindValue = ref.getBind();
@@ -218,15 +214,24 @@
                         boolean createUnbind = false;
 
                         // Only create method if no bind name has been specified
-                        if (bindValue == null && validator.findMethod(ref, "bind") == null) {
+                        if (bindValue == null && Validator.findMethod(this.project, this.options, container.getClassDescription(), ref, "bind") == null) {
                             // create bind method
                             createBind = true;
                         }
-                        if (unbindValue == null && validator.findMethod(ref, "unbind") == null) {
+                        if (unbindValue == null && Validator.findMethod(this.project, this.options, container.getClassDescription(), ref, "unbind") == null) {
                             // create unbind method
                             createUnbind = true;
                         }
                         if (createBind || createUnbind) {
+                            // logging
+                            if ( createBind && createUnbind ) {
+                                this.logger.debug("Generating bind and unbind method for " + name + " in " + container.getClassDescription().getClass().getName());
+                            } else if ( createBind ) {
+                                this.logger.debug("Generating bind method for " + name + " in " + container.getClassDescription().getClass().getName());
+                            } else {
+                                this.logger.debug("Generating unbind method for " + name + " in " + container.getClassDescription().getClass().getName());
+
+                            }
                             ClassModifier.addMethods(container.getClassDescription().getDescribedClass().getName(),
                                             name,
                                             ref.getField().getName(),
@@ -238,7 +243,13 @@
                     }
                 }
             }
+        }
 
+        // now validate
+        for (final ComponentContainer container : processedContainers) {
+            final int errorCount = iLog.getNumberOfErrors();
+
+            final Validator validator = new Validator(container, project, options, iLog);
             validator.validate();
 
             // ignore component if it has errors
@@ -251,7 +262,6 @@
                 }
             }
         }
-
         // log issues
         iLog.logMessages(logger);
 
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/AbstractDescription.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/AbstractDescription.java
index 1d10c0c..b2dd8fc 100644
--- a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/AbstractDescription.java
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/AbstractDescription.java
@@ -71,4 +71,6 @@
     public String getIdentifier() {
         return this.annotationPrefix;
     }
+
+    public abstract AbstractDescription clone();
 }
\ No newline at end of file
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ClassDescription.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ClassDescription.java
index a8b8a53..0a8ceee 100644
--- a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ClassDescription.java
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ClassDescription.java
@@ -111,4 +111,12 @@
                         + ", describedClass=" + describedClass + ", source=" + source
                         + "]";
     }
+
+    public ClassDescription clone() {
+        final ClassDescription cd = new ClassDescription(this.describedClass, this.source);
+        for(final AbstractDescription ad : this.descriptions) {
+            cd.add(ad.clone());
+        }
+        return cd;
+    }
 }
\ No newline at end of file
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ComponentDescription.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ComponentDescription.java
index 11c1bfa..a0f3d3f 100644
--- a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ComponentDescription.java
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ComponentDescription.java
@@ -250,6 +250,14 @@
         }
     }
 
+    public String getConfigurationPid() {
+        return configurationPid;
+    }
+
+    public void setConfigurationPid(String configurationPid) {
+        this.configurationPid = configurationPid;
+    }
+
     @Override
     public String toString() {
         return "ComponentDescription [name=" + name + ", label=" + label + ", description=" + description
@@ -261,11 +269,28 @@
                         + configurationPid + "]";
     }
 
-    public String getConfigurationPid() {
-        return configurationPid;
-    }
+    @Override
+    public AbstractDescription clone() {
+        final ComponentDescription cd = new ComponentDescription(this.annotation);
+        cd.setName(this.getName());
+        cd.setLabel(this.getLabel());
+        cd.setDescription(this.getDescription());
+        cd.setConfigurationPolicy(this.getConfigurationPolicy());
+        cd.setAbstract(this.isAbstract);
+        cd.setInherit(this.isInherit);
+        cd.setCreateDs(this.isCreateDs());
+        cd.setCreateMetatype(this.isCreateMetatype());
+        cd.setCreatePid(this.isCreatePid());
+        cd.setEnabled(this.getEnabled());
+        cd.setImmediate(this.getImmediate());
+        cd.setFactory(this.getFactory());
+        cd.setSetMetatypeFactoryPid(this.isSetMetatypeFactoryPid());
+        cd.setActivate(this.getActivate());
+        cd.setDeactivate(this.getDeactivate());
+        cd.setModified(this.getModified());
+        cd.setSpecVersion(this.getSpecVersion());
+        cd.setConfigurationPid(this.getConfigurationPid());
 
-    public void setConfigurationPid(String configurationPid) {
-        this.configurationPid = configurationPid;
+        return cd;
     }
 }
\ No newline at end of file
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/PropertyDescription.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/PropertyDescription.java
index e9bacb0..9520539 100644
--- a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/PropertyDescription.java
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/PropertyDescription.java
@@ -156,4 +156,19 @@
                 + ", options=" + Arrays.toString(options) + ", annotation=" + annotation + "]";
     }
 
+    @Override
+    public AbstractDescription clone() {
+        final PropertyDescription cd = new PropertyDescription(this.annotation);
+        cd.setName(this.getName());
+        cd.setLabel(this.getLabel());
+        cd.setDescription(this.getDescription());
+        cd.setValue(this.getValue());
+        cd.setType(this.getType());
+        cd.setMultiValue(this.getMultiValue());
+        cd.setUnbounded(this.getUnbounded());
+        cd.setCardinality(this.getCardinality());
+        cd.setPrivate(this.isPrivate());
+        cd.setOptions(this.getOptions());
+        return cd;
+    }
 }
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ReferenceDescription.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ReferenceDescription.java
index 3ec48ff..0c2da4b 100644
--- a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ReferenceDescription.java
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ReferenceDescription.java
@@ -146,6 +146,14 @@
         this.strategy = strategy;
     }
 
+    public Field getField() {
+        return field;
+    }
+
+    public void setField(Field field) {
+        this.field = field;
+    }
+
     @Override
     public String toString() {
         return "ReferenceDescription [name=" + name + ", interfaceName="
@@ -157,11 +165,21 @@
                 + "]";
     }
 
-    public Field getField() {
-        return field;
-    }
+    @Override
+    public AbstractDescription clone() {
+        final ReferenceDescription cd = new ReferenceDescription(this.annotation);
+        cd.setName(this.getName());
+        cd.setInterfaceName(this.getInterfaceName());
+        cd.setTarget(this.getTarget());
+        cd.setCardinality(this.getCardinality());
+        cd.setPolicy(this.getPolicy());
+        cd.setPolicyOption(this.getPolicyOption());
+        cd.setStrategy(this.getStrategy());
+        cd.setField(this.getField());
+        cd.setBind(this.getBind());
+        cd.setUnbind(this.getUnbind());
+        cd.setUpdated(this.getUpdated());
 
-    public void setField(Field field) {
-        this.field = field;
+        return cd;
     }
 }
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ServiceDescription.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ServiceDescription.java
index bf3c9f2..b083dc5 100644
--- a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ServiceDescription.java
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ServiceDescription.java
@@ -68,4 +68,15 @@
                 + ", interfaces=" + interfaces + ", annotation=" + annotation
                 + "]";
     }
+
+    @Override
+    public AbstractDescription clone() {
+        final ServiceDescription cd = new ServiceDescription(this.annotation);
+        cd.setServiceFactory(this.isServiceFactory);
+        for(final String i : this.getInterfaces()) {
+            cd.addInterface(i);
+        }
+
+        return cd;
+    }
 }
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 3d7cae6..f36420c 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
@@ -365,7 +365,7 @@
             // and cache
             allDescriptions.put(name, result);
         }
-        return result;
+        return result.clone();
     }
 
     /**
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/helper/Validator.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/helper/Validator.java
index 593bb4c..ac226c1 100644
--- a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/helper/Validator.java
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/helper/Validator.java
@@ -28,6 +28,7 @@
 import org.apache.felix.scrplugin.SCRDescriptorException;
 import org.apache.felix.scrplugin.SpecVersion;
 import org.apache.felix.scrplugin.description.AbstractDescription;
+import org.apache.felix.scrplugin.description.ClassDescription;
 import org.apache.felix.scrplugin.description.ComponentDescription;
 import org.apache.felix.scrplugin.description.PropertyDescription;
 import org.apache.felix.scrplugin.description.PropertyType;
@@ -59,11 +60,23 @@
     }
 
     private void logWarn(final AbstractDescription desc, final String message) {
-        iLog.addWarning(desc.getIdentifier() + " : " + message, desc.getSource());
+        // check if location of description is the same as the class
+        final String classLocation = this.container.getComponentDescription().getSource();
+        if ( classLocation.equals(desc.getSource()) ) {
+            iLog.addWarning(desc.getIdentifier() + " : " + message, desc.getSource());
+        } else {
+            iLog.addWarning(desc.getIdentifier() + " (" + desc.getSource() + ") : " + message, classLocation);
+        }
     }
 
     private void logError(final AbstractDescription desc, final String message) {
-        iLog.addError(desc.getIdentifier() + " : " + message, desc.getSource());
+        // check if location of description is the same as the class
+        final String classLocation = this.container.getComponentDescription().getSource();
+        if ( classLocation.equals(desc.getSource()) ) {
+            iLog.addError(desc.getIdentifier() + " : " + message, desc.getSource());
+        } else {
+            iLog.addError(desc.getIdentifier() + " (" + desc.getSource() + ") : " + message, classLocation);
+        }
     }
 
     /**
@@ -201,7 +214,7 @@
                 }
             }
         }
-        return this.getMethod(name, classSig);
+        return getMethod(this.container.getClassDescription(), name, classSig);
     }
 
     /**
@@ -434,6 +447,9 @@
 
             if ( bindName != null ) {
                 bindName = this.validateMethod(ref, bindName, componentIsAbstract);
+                if ( bindName == null && ref.getField() != null ) {
+                    iLog.addError("Something went wrong: " + canGenerate + " - " + this.options.isGenerateAccessors() + " - " + ref.getCardinality(), ref.getField().getName());
+                }
             } else {
                 bindName = "bind" + Character.toUpperCase(ref.getName().charAt(0)) + ref.getName().substring(1);
             }
@@ -464,10 +480,10 @@
 
     private String validateMethod(final ReferenceDescription ref, final String methodName, final boolean componentIsAbstract)
     throws SCRDescriptorException {
-        final Method method = this.findMethod(ref, methodName);
+        final Method method = findMethod(this.project, this.options, this.container.getClassDescription(), ref, methodName);
         if (method == null) {
             if (!componentIsAbstract) {
-                this.logError(this.container.getComponentDescription(),
+                this.logError(ref,
                                 "Missing method " + methodName + " for reference "
                                                 + (ref.getName() == null ? "" : ref.getName()));
             }
@@ -488,8 +504,8 @@
 
     private static final String TYPE_SERVICE_REFERENCE = "org.osgi.framework.ServiceReference";
 
-    private Method getMethod(final String name, final Class<?>[] sig) {
-        Class<?> checkClass = this.container.getClassDescription().getDescribedClass();
+    private static Method getMethod(final ClassDescription cd, final String name, final Class<?>[] sig) {
+        Class<?> checkClass = cd.getDescribedClass();
         while ( checkClass != null ) {
             try {
                 return checkClass.getDeclaredMethod(name, sig);
@@ -503,20 +519,24 @@
         return null;
     }
 
-    public Method findMethod(final ReferenceDescription ref, final String methodName)
+    public static Method findMethod(final Project project,
+                    final Options options,
+                    final ClassDescription cd,
+                    final ReferenceDescription ref,
+                    final String methodName)
     throws SCRDescriptorException {
         try {
-            final Class<?>[] sig = new Class<?>[] { this.project.getClassLoader().loadClass(TYPE_SERVICE_REFERENCE) };
-            final Class<?>[] sig2 = new Class<?>[] { this.project.getClassLoader().loadClass(ref.getInterfaceName()) };
-            final Class<?>[] sig3 = new Class<?>[] { this.project.getClassLoader().loadClass(ref.getInterfaceName()), Map.class };
+            final Class<?>[] sig = new Class<?>[] { project.getClassLoader().loadClass(TYPE_SERVICE_REFERENCE) };
+            final Class<?>[] sig2 = new Class<?>[] { project.getClassLoader().loadClass(ref.getInterfaceName()) };
+            final Class<?>[] sig3 = new Class<?>[] { project.getClassLoader().loadClass(ref.getInterfaceName()), Map.class };
 
             // service interface or ServiceReference first
             String realMethodName = methodName;
-            Method method = getMethod(realMethodName, sig);
+            Method method = getMethod(cd, realMethodName, sig);
             if (method == null) {
-                method = getMethod(realMethodName, sig2);
-                if (method == null && this.options.getSpecVersion().ordinal() >= SpecVersion.VERSION_1_1.ordinal() ) {
-                    method = getMethod(realMethodName, sig3);
+                method = getMethod(cd, realMethodName, sig2);
+                if (method == null && options.getSpecVersion().ordinal() >= SpecVersion.VERSION_1_1.ordinal() ) {
+                    method = getMethod(cd, realMethodName, sig3);
                 }
             }
 
@@ -532,12 +552,12 @@
                 }
                 realMethodName = methodName + Character.toUpperCase(info.charAt(0)) + info.substring(1);
 
-                method = getMethod(realMethodName, sig);
+                method = getMethod(cd, realMethodName, sig);
             }
             if (method == null) {
-                method = getMethod(realMethodName, sig2);
-                if (method == null && this.options.getSpecVersion().ordinal() >= SpecVersion.VERSION_1_1.ordinal() ) {
-                    method = getMethod(realMethodName, sig3);
+                method = getMethod(cd, realMethodName, sig2);
+                if (method == null && options.getSpecVersion().ordinal() >= SpecVersion.VERSION_1_1.ordinal() ) {
+                    method = getMethod(cd, realMethodName, sig3);
                 }
             }
 
@@ -545,12 +565,12 @@
             if (method == null) {
                 int lastDot = ref.getInterfaceName().lastIndexOf('.');
                 realMethodName = methodName + ref.getInterfaceName().substring(lastDot + 1);
-                method = getMethod(realMethodName, sig);
+                method = getMethod(cd, realMethodName, sig);
             }
             if (method == null) {
-                method = getMethod(realMethodName, sig2);
-                if (method == null && this.options.getSpecVersion().ordinal() >= SpecVersion.VERSION_1_1.ordinal() ) {
-                    method = getMethod(realMethodName, sig3);
+                method = getMethod(cd, realMethodName, sig2);
+                if (method == null && options.getSpecVersion().ordinal() >= SpecVersion.VERSION_1_1.ordinal() ) {
+                    method = getMethod(cd, realMethodName, sig3);
                 }
             }
 
diff --git a/scrplugin/maven-scr-plugin/src/main/java/org/apache/felix/scrplugin/mojo/MavenProjectScanner.java b/scrplugin/maven-scr-plugin/src/main/java/org/apache/felix/scrplugin/mojo/MavenProjectScanner.java
index 6c45835..f58a21f 100644
--- a/scrplugin/maven-scr-plugin/src/main/java/org/apache/felix/scrplugin/mojo/MavenProjectScanner.java
+++ b/scrplugin/maven-scr-plugin/src/main/java/org/apache/felix/scrplugin/mojo/MavenProjectScanner.java
@@ -27,7 +27,6 @@
 
 import org.apache.felix.scrplugin.Log;
 import org.apache.felix.scrplugin.Source;
-import org.apache.felix.scrplugin.helper.StringUtils;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.util.DirectoryScanner;
@@ -65,12 +64,12 @@
         // FELIX-509: check for excludes
         String[] includes = new String[] { "**/*.java" };
         if ( includeString != null ) {
-        	includes = StringUtils.split( includeString, "," );
+        	includes = includeString.split( "," );
         }
 
         final String[] excludes;
         if ( excludeString != null ) {
-            excludes = StringUtils.split( excludeString, "," );
+            excludes = excludeString.split( "," );
         } else {
             excludes = null;
         }
diff --git a/scrplugin/maven-scr-plugin/src/main/java/org/apache/felix/scrplugin/mojo/SCRDescriptorMojo.java b/scrplugin/maven-scr-plugin/src/main/java/org/apache/felix/scrplugin/mojo/SCRDescriptorMojo.java
index 8a2dce4..2474b5d 100644
--- a/scrplugin/maven-scr-plugin/src/main/java/org/apache/felix/scrplugin/mojo/SCRDescriptorMojo.java
+++ b/scrplugin/maven-scr-plugin/src/main/java/org/apache/felix/scrplugin/mojo/SCRDescriptorMojo.java
@@ -161,16 +161,15 @@
     public void execute() throws MojoExecutionException, MojoFailureException {
         // create the log for the generator
         final org.apache.felix.scrplugin.Log scrLog = new MavenLog(getLog());
-        // create the class loader
-        final ClassLoader classLoader = new URLClassLoader(getClassPath(), this
-                .getClass().getClassLoader());
 
         // create project
         final MavenProjectScanner scanner = new MavenProjectScanner(
                 this.project, this.sourceIncludes, this.sourceExcludes, scrLog);
 
         final Project project = new Project();
-        project.setClassLoader(classLoader);
+        // create the class loader
+        project.setClassLoader(new URLClassLoader(getClassPath(), this
+                                .getClass().getClassLoader()));
         project.setDependencies(scanner.getDependencies());
         project.setSources(scanner.getSources());
         project.setClassesDirectory(this.project.getBuild().getOutputDirectory());
diff --git a/scrplugin/scrtask/src/main/java/org/apache/felix/scrplugin/ant/SCRDescriptorTask.java b/scrplugin/scrtask/src/main/java/org/apache/felix/scrplugin/ant/SCRDescriptorTask.java
index dbea73b..f55fda6 100644
--- a/scrplugin/scrtask/src/main/java/org/apache/felix/scrplugin/ant/SCRDescriptorTask.java
+++ b/scrplugin/scrtask/src/main/java/org/apache/felix/scrplugin/ant/SCRDescriptorTask.java
@@ -100,9 +100,9 @@
 
         try {
             final Path classPath = createClasspath();
-            final ClassLoader classLoader = getClassLoader( this.getClass().getClassLoader() );
             final org.apache.felix.scrplugin.Project project = new org.apache.felix.scrplugin.Project();
-            project.setClassLoader(classLoader);
+            project.setClassLoader(getClassLoader( this.getClass().getClassLoader() ));
+
             project.setDependencies(getDependencies(classPath));
             project.setSources(getSourceFiles(getImplicitFileSet()));
             project.setClassesDirectory(destdir.getAbsolutePath());