FELIX-645 : If a reference is already complete in a super class, don't check it again in a subclass.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@679737 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/Constants.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/Constants.java
index 7ea1927..077c732 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/Constants.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/Constants.java
@@ -97,6 +97,8 @@
 
     public static final String REFERENCE_UNDBIND = "unbind";
 
+    public static final String REFERENCE_CHECKED = "checked";
+
     public static final String ABSTRACT_DESCRIPTOR_FILENAME = "scrinfo.xml";
 
     public static final String ABSTRACT_DESCRIPTOR_RELATIVE_PATH = "OSGI-INF" + File.separator + "scr-plugin" + File.separator + ABSTRACT_DESCRIPTOR_FILENAME;
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorMojo.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorMojo.java
index ea095b4..65b53bb 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorMojo.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorMojo.java
@@ -510,6 +510,10 @@
         if ( unbindValue != null ) {
             ref.setUnbind(unbindValue);
         }
+        final String isChecked = reference.getNamedParameter(Constants.REFERENCE_CHECKED);
+        if ( isChecked != null ) {
+            ref.setChecked(Boolean.valueOf(isChecked).booleanValue());
+        }
         // if this is a field with a single cardinality,
         // we look for the bind/unbind methods
         // and create them if they are not availabe
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Component.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Component.java
index 93e46a9..70055cc 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Component.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Component.java
@@ -182,6 +182,7 @@
      */
     public void validate(List issues, List warnings)
     throws MojoExecutionException {
+        final int currentIssueCount = issues.size();
 
         // nothing to check if this is ignored
         if (!isDs()) {
@@ -204,7 +205,7 @@
                 }
 
                 // no errors so far, let's continue
-                if ( issues.size() == 0 ) {
+                if ( issues.size() == currentIssueCount ) {
                     // check activate and deactivate methods
                     this.checkLifecycleMethod(javaClass, "activate", warnings);
                     this.checkLifecycleMethod(javaClass, "deactivate", warnings);
@@ -249,17 +250,18 @@
                     if (isServiceFactory && this.isImmediate() != null && this.isImmediate().booleanValue() && this.getFactory() != null) {
                         issues.add(this.getMessage("Component must not be a ServiceFactory, if immediate and/or component factory: " + javaClass.getName()));
                     }
-                    
+
                     // immediate must not be true for component factory
                     if (this.isImmediate() != null && this.isImmediate().booleanValue() && this.getFactory() != null) {
                         issues.add(this.getMessage("Component must not be immediate if component factory: " + javaClass.getName()));
                     }
-
-                    // verify references
-                    for (Iterator ri = this.getReferences().iterator(); ri.hasNext();) {
-                        final Reference ref = (Reference) ri.next();
-                        ref.validate(issues, warnings);
-                    }
+                }
+            }
+            if ( issues.size() == currentIssueCount ) {
+                // verify references
+                for (Iterator ri = this.getReferences().iterator(); ri.hasNext();) {
+                    final Reference ref = (Reference) ri.next();
+                    ref.validate(issues, warnings, this.isAbstract);
                 }
             }
         }
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Reference.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Reference.java
index 79f13d5..1dbbb9d 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Reference.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/Reference.java
@@ -20,9 +20,7 @@
 
 import java.util.List;
 
-import org.apache.felix.scrplugin.tags.JavaClassDescription;
-import org.apache.felix.scrplugin.tags.JavaMethod;
-import org.apache.felix.scrplugin.tags.JavaTag;
+import org.apache.felix.scrplugin.tags.*;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.codehaus.plexus.util.StringUtils;
 
@@ -40,6 +38,10 @@
     protected String bind;
     protected String unbind;
 
+    /** Is this reference already checked? */
+    protected boolean checked = false;
+
+    /** The class description containing this reference. */
     protected final JavaClassDescription javaClassDescription;
 
     /**
@@ -116,13 +118,27 @@
         this.unbind = unbind;
     }
 
+    public boolean isChecked() {
+        return checked;
+    }
+
+    public void setChecked(boolean checked) {
+        this.checked = checked;
+    }
+
     /**
      * Validate the property.
      * If errors occur a message is added to the issues list,
      * warnings can be added to the warnings list.
      */
-    public void validate(List issues, List warnings)
+    public void validate(List issues, List warnings, boolean componentIsAbstract)
     throws MojoExecutionException {
+        // if this reference is already checked, return immediately
+        if ( this.checked ) {
+            return;
+        }
+        final int currentIssueCount = issues.size();
+
         // validate name
         if (StringUtils.isEmpty(this.name)) {
             issues.add(this.getMessage("Reference has no name"));
@@ -149,17 +165,35 @@
         }
 
         // validate bind and unbind methods
-        this.bind = this.validateMethod(this.bind, issues, warnings);
-        this.unbind = this.validateMethod(this.unbind, issues, warnings);
+        final String oldBind = this.bind;
+        final String oldUnbind = this.unbind;
+        this.bind = this.validateMethod(this.bind, issues, warnings, componentIsAbstract);
+        this.unbind = this.validateMethod(this.unbind, issues, warnings, componentIsAbstract);
+        if ( issues.size() == currentIssueCount ) {
+            if ( this.bind != null && this.unbind != null ) {
+                // no errors, so we're checked
+                this.checked = true;
+            } else {
+                if ( this.bind == null ) {
+                    this.bind = oldBind;
+                }
+                if ( this.unbind == null ) {
+                    this.unbind = oldUnbind;
+                }
+            }
+        }
     }
 
-    protected String validateMethod(String methodName, List issues, List warnings)
+    protected String validateMethod(String  methodName,
+                                    List    issues,
+                                    List    warnings,
+                                    boolean componentIsAbstract)
     throws MojoExecutionException {
-
-        JavaMethod method = this.findMethod(methodName);
-
+        final JavaMethod method = this.findMethod(methodName);
         if (method == null) {
-            issues.add(this.getMessage("Missing method " + methodName + " for reference " + this.getName()));
+            if ( !componentIsAbstract ) {
+                issues.add(this.getMessage("Missing method " + methodName + " for reference " + this.getName()));
+            }
             return null;
         }
 
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/cl/ClassLoaderJavaTag.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/cl/ClassLoaderJavaTag.java
index d53bec6..17f5dc9 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/cl/ClassLoaderJavaTag.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/tags/cl/ClassLoaderJavaTag.java
@@ -112,6 +112,7 @@
             map.put(Constants.REFERENCE_POLICY, this.reference.getPolicy());
             map.put(Constants.REFERENCE_TARGET, this.reference.getTarget());
             map.put(Constants.REFERENCE_UNDBIND, this.reference.getUnbind());
+            map.put(Constants.REFERENCE_CHECKED, String.valueOf(this.reference.isChecked()));
             return map;
         } else if ( this.property != null ) {
             final Map map = new HashMap();
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/xml/ComponentDescriptorIO.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/xml/ComponentDescriptorIO.java
index 916e618..da54969 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/xml/ComponentDescriptorIO.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/xml/ComponentDescriptorIO.java
@@ -161,7 +161,7 @@
             final Iterator i = component.getReferences().iterator();
             while ( i.hasNext() ) {
                 final Reference reference = (Reference)i.next();
-                generateXML(reference, contentHandler);
+                generateXML(reference, contentHandler, isScrPrivateFile);
             }
         }
         IOUtils.indent(contentHandler, 1);
@@ -273,7 +273,7 @@
      * @param contentHandler
      * @throws SAXException
      */
-    protected static void generateXML(Reference reference, ContentHandler contentHandler)
+    protected static void generateXML(Reference reference, ContentHandler contentHandler, boolean isScrPrivateFile)
     throws SAXException {
         final AttributesImpl ai = new AttributesImpl();
         IOUtils.addAttribute(ai, "name", reference.getName());
@@ -283,6 +283,9 @@
         IOUtils.addAttribute(ai, "target", reference.getTarget());
         IOUtils.addAttribute(ai, "bind", reference.getBind());
         IOUtils.addAttribute(ai, "unbind", reference.getUnbind());
+        if ( isScrPrivateFile ) {
+            IOUtils.addAttribute(ai, "checked", String.valueOf(reference.isChecked()));
+        }
         IOUtils.indent(contentHandler, 2);
         contentHandler.startElement(NAMESPACE_URI, ComponentDescriptorIO.REFERENCE, ComponentDescriptorIO.REFERENCE_QNAME, ai);
         contentHandler.endElement(NAMESPACE_URI, ComponentDescriptorIO.REFERENCE, ComponentDescriptorIO.REFERENCE_QNAME);
@@ -404,6 +407,10 @@
                     ref.setBind(attributes.getValue("bind"));
                     ref.setUnbind(attributes.getValue("unbind"));
 
+                    if ( attributes.getValue("checked") != null ) {
+                        ref.setChecked(Boolean.valueOf(attributes.getValue("checked")).booleanValue());
+                    }
+
                     this.currentComponent.addReference(ref);
                 }
             }