FELIX-1229 : Add support for new bind and unbind signatures

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@784157 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 db2a641..cf019df 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/Constants.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/Constants.java
@@ -132,8 +132,10 @@
 
     public static final String REFERENCE_CHECKED = "checked";
 
-    /** @since 1.0.9 */
+    /** Lookup strategy for references @since 1.0.9 */
     public static final String REFERENCE_STRATEGY = "strategy";
+    public static final String REFERENCE_STRATEGY_LOOKUP = "lookup";
+    public static final String REFERENCE_STRATEGY_EVENT = "event";
 
     public static final String ABSTRACT_DESCRIPTOR_FILENAME = "scrinfo.xml";
 
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 f07c646..b8a0bca 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorMojo.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorMojo.java
@@ -126,6 +126,13 @@
     private String[] annotationTagProviders = {};
 
     /**
+     * The version of the DS spec this plugin generates a descriptor for.
+     * By default the version is detected by the used tags.
+     * @parameter
+     */
+    private String specVersion;
+
+    /**
      * @see org.apache.maven.plugin.AbstractMojo#execute()
      */
     public void execute() throws MojoExecutionException, MojoFailureException {
@@ -134,6 +141,17 @@
         this.getLog().debug("..parsing javadocs: " + this.parseJavadoc);
         this.getLog().debug("..processing annotations: " + this.processAnnotations);
 
+        // check speck version configuration
+        int specVersion = Constants.VERSION_1_0;
+        if ( this.specVersion != null ) {
+            if ( this.specVersion.equals("1.1") ) {
+                specVersion = Constants.VERSION_1_1;
+            } else if ( !this.specVersion.equals("1.0") ) {
+                throw new MojoExecutionException("Unknown configuration for spec version: " + this.specVersion);
+            }
+        } else {
+            this.getLog().debug("..auto detecting spec version");
+        }
         JavaClassDescriptorManager jManager = new JavaClassDescriptorManager(this.getLog(),
                                                                              this.project,
                                                                              this.annotationTagProviders,
@@ -149,7 +167,6 @@
         final JavaClassDescription[] javaSources = jManager.getSourceDescriptions();
         Arrays.sort(javaSources, new JavaClassDescriptionInheritanceComparator());
 
-        int specVersion = Constants.VERSION_1_0;
         final List<Component> scannedComponents = new ArrayList<Component>();
         for (int i = 0; i < javaSources.length; i++) {
             this.getLog().debug("Testing source " + javaSources[i].getName());
@@ -163,12 +180,22 @@
                 } else {
                     final Component comp = this.createComponent(javaSources[i], tag, metaData, iLog);
                     if ( comp.getSpecVersion() > specVersion ) {
+                        // if a spec version has been configured and a component requires a higher
+                        // version, this is considered an error!
+                        if ( this.specVersion != null ) {
+                            String v = "1.0";
+                            if ( comp.getSpecVersion() == Constants.VERSION_1_1 ) {
+                                v = "1.1";
+                            }
+                            iLog.addError("Component " + comp + " requires spec version " + v + " but plugin is configured to use version " + this.specVersion);
+                        }
                         specVersion = comp.getSpecVersion();
                     }
                     scannedComponents.add(comp);
                 }
             }
         }
+        this.getLog().debug("..generating descriptor for spec version: " + this.specVersion);
 
         // now check for abstract components and fill components objects
         final Components components = new Components();
@@ -178,6 +205,39 @@
 
         for(final Component comp : scannedComponents ) {
             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
+
+            for(final Reference ref : comp.getReferences() ) {
+                // 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 ( this.generateAccessors && !ref.isLookupStrategy() ) {
+                    if ( ref.getJavaTag().getField() != null && comp.getJavaClassDescription() instanceof ModifiableJavaClassDescription ) {
+                        if ( ref.getCardinality().equals("0..1") || ref.getCardinality().equals("1..1") ) {
+                            final String bindValue = ref.getBind();
+                            final String unbindValue = ref.getUnbind();
+                            final String name = ref.getName();
+                            final String type = ref.getInterfacename();
+
+                            boolean createBind = false;
+                            boolean createUnbind = false;
+                            // Only create method if no bind name has been specified
+                            if ( bindValue == null && ref.findMethod(specVersion, ref.getBind()) == null ) {
+                                // create bind method
+                                createBind = true;
+                            }
+                            if ( unbindValue == null && ref.findMethod(specVersion, ref.getUnbind()) == null ) {
+                                // create unbind method
+                                createUnbind = true;
+                            }
+                            if ( createBind || createUnbind ) {
+                                ((ModifiableJavaClassDescription)comp.getJavaClassDescription()).addMethods(name, type, createBind, createUnbind);
+                            }
+                        }
+                    }
+                }
+            }
             comp.validate(specVersion, iLog);
             // ignore component if it has errors
             if ( iLog.getNumberOfErrors() == errorCount ) {
@@ -648,29 +708,6 @@
             ref.setStrategy(strategy);
         }
 
-        // 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 ( this.generateAccessors && !ref.isLookupStrategy() ) {
-            if ( reference.getField() != null && component.getJavaClassDescription() instanceof ModifiableJavaClassDescription ) {
-                if ( ref.getCardinality().equals("0..1") || ref.getCardinality().equals("1..1") ) {
-                    boolean createBind = false;
-                    boolean createUnbind = false;
-                    // Only create method if no bind name has been specified
-                    if ( bindValue == null && ref.findMethod(ref.getBind()) == null ) {
-                        // create bind method
-                        createBind = true;
-                    }
-                    if ( unbindValue == null && ref.findMethod(ref.getUnbind()) == null ) {
-                        // create unbind method
-                        createUnbind = true;
-                    }
-                    if ( createBind || createUnbind ) {
-                        ((ModifiableJavaClassDescription)component.getJavaClassDescription()).addMethods(name, type, createBind, createUnbind);
-                    }
-                }
-            }
-        }
         component.addReference(ref);
     }
 
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/AbstractObject.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/AbstractObject.java
index 92d5a94..f5d0f58 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/om/AbstractObject.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/om/AbstractObject.java
@@ -38,4 +38,8 @@
         }
         return "@" + this.tag.getName() + ": " + message + " (" + this.tag.getSourceLocation() + ")";
     }
+
+    public JavaTag getJavaTag() {
+        return this.tag;
+    }
 }
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 c8367f4..b953725 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
@@ -18,6 +18,7 @@
  */
 package org.apache.felix.scrplugin.om;
 
+import org.apache.felix.scrplugin.Constants;
 import org.apache.felix.scrplugin.IssueLog;
 import org.apache.felix.scrplugin.tags.*;
 import org.apache.maven.plugin.MojoExecutionException;
@@ -140,7 +141,7 @@
 
     /** @since 1.0.9 */
     public boolean isLookupStrategy() {
-        return "lookup".equals(getStrategy());
+        return Constants.REFERENCE_STRATEGY_LOOKUP.equals(getStrategy());
     }
 
     /**
@@ -185,17 +186,18 @@
 
         // validate strategy
         if (this.strategy == null) {
-            this.strategy = "event";
-        } else if (!"event".equals(this.strategy) && !"lookup".equals(this.strategy)) {
-            iLog.addError(this.getMessage("Invalid startegy type " + this.strategy));
+            this.strategy = Constants.REFERENCE_STRATEGY_EVENT;
+        } else if (!Constants.REFERENCE_STRATEGY_EVENT.equals(this.strategy)
+                   && !Constants.REFERENCE_STRATEGY_LOOKUP.equals(this.strategy)) {
+            iLog.addError(this.getMessage("Invalid strategy type " + this.strategy));
         }
 
         // validate bind and unbind methods
         if (!isLookupStrategy()) {
             final String oldBind = this.bind;
             final String oldUnbind = this.unbind;
-            this.bind = this.validateMethod(this.bind, componentIsAbstract, iLog);
-            this.unbind = this.validateMethod(this.unbind, componentIsAbstract, iLog);
+            this.bind = this.validateMethod(specVersion, this.bind, componentIsAbstract, iLog);
+            this.unbind = this.validateMethod(specVersion, this.unbind, componentIsAbstract, iLog);
             if ( iLog.getNumberOfErrors() == currentIssueCount ) {
                 if ( this.bind != null && this.unbind != null ) {
                     // no errors, so we're checked
@@ -215,11 +217,12 @@
         }
     }
 
-    protected String validateMethod(String  methodName,
-                                    boolean componentIsAbstract,
-                                    final   IssueLog iLog)
+    protected String validateMethod(final int      specVersion,
+                                    final String   methodName,
+                                    final boolean  componentIsAbstract,
+                                    final IssueLog iLog)
     throws MojoExecutionException {
-        final JavaMethod method = this.findMethod(methodName);
+        final JavaMethod method = this.findMethod(specVersion, methodName);
         if (method == null) {
             if ( !componentIsAbstract ) {
                 iLog.addError(this.getMessage("Missing method " + methodName + " for reference " + this.getName()));
@@ -237,16 +240,24 @@
         return method.getName();
     }
 
-    public JavaMethod findMethod(String methodName)
+    private static final String TYPE_SERVICE_REFERENCE = "org.osgi.framework.ServiceReference";
+    private static final String TYPE_MAP = "java.util.Map";
+
+    public JavaMethod findMethod(final int    specVersion,
+                                 final String methodName)
     throws MojoExecutionException {
-        String[] sig = new String[]{ this.getInterfacename() };
-        String[] sig2 = new String[]{ "org.osgi.framework.ServiceReference" };
+        final String[] sig = new String[]{ TYPE_SERVICE_REFERENCE };
+        final String[] sig2 = new String[]{ this.getInterfacename() };
+        final String[] sig3 = new String[]{ this.getInterfacename(), TYPE_MAP};
 
         // service interface or ServiceReference first
         String realMethodName = methodName;
         JavaMethod method = this.javaClassDescription.getMethodBySignature(realMethodName, sig);
         if (method == null) {
             method = this.javaClassDescription.getMethodBySignature(realMethodName, sig2);
+            if ( specVersion == Constants.VERSION_1_1 && method == null ) {
+                method = this.javaClassDescription.getMethodBySignature(realMethodName, sig3);
+            }
         }
 
         // append reference name with service interface and ServiceReference
@@ -258,6 +269,9 @@
         }
         if (method == null) {
             method = this.javaClassDescription.getMethodBySignature(realMethodName, sig2);
+            if ( specVersion == Constants.VERSION_1_1 && method == null ) {
+                method = this.javaClassDescription.getMethodBySignature(realMethodName, sig3);
+            }
         }
 
         // append type name with service interface and ServiceReference
@@ -269,6 +283,9 @@
         }
         if (method == null) {
             method = this.javaClassDescription.getMethodBySignature(realMethodName, sig2);
+            if ( specVersion == Constants.VERSION_1_1 && method == null ) {
+                method = this.javaClassDescription.getMethodBySignature(realMethodName, sig3);
+            }
         }
 
         return method;