FELIX-1703 Add support do declare the DS specification version
explicitly on a per-component basis using the same attribute
name (specVersion) as is used to set the global spec version
per plugin configuration

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@822151 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 06dab72..dd62465 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/Constants.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/Constants.java
@@ -61,6 +61,15 @@
 
     public static final String COMPONENT_DS = "ds";
 
+    // Force the descriptor version (since 1.4.1)
+    public static final String COMPONENT_DS_SPEC_VERSION = "specVersion";
+
+    // Specification version identifier for SCR 1.0 (R 4.1)
+    public static final String COMPONENT_DS_SPEC_VERSION_10 = "1.0";
+
+    // Specification version identifier for SCR 1.1 (R 4.2)
+    public static final String COMPONENT_DS_SPEC_VERSION_11 = "1.1";
+
     public static final String COMPONENT_CREATE_PID = "create-pid";
 
     public static final String COMPONENT_SET_METATYPE_FACTORY_PID = "configurationFactory";
diff --git a/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorGenerator.java b/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorGenerator.java
index 7dc3f74..44aed05 100644
--- a/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorGenerator.java
+++ b/scrplugin/src/main/java/org/apache/felix/scrplugin/SCRDescriptorGenerator.java
@@ -234,22 +234,16 @@
         this.logger.debug( "..processing annotations: " + this.descriptorManager.isProcessAnnotations() );
 
         // 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 SCRDescriptorException( "Unknown configuration for spec version: " + this.specVersion );
-            }
-        }
-        else
+        int specVersion = toSpecVersionCode( this.specVersion );
+        if ( this.specVersion == null )
         {
             this.logger.debug( "..auto detecting spec version" );
         }
+        else
+        {
+            this.logger.debug( "..using spec version " + this.specVersion + " (" + specVersion + ")" );
+        }
+
         final IssueLog iLog = new IssueLog( this.strictMode );
 
         final MetaData metaData = new MetaData();
@@ -282,10 +276,10 @@
                         // version, this is considered an error!
                         if ( this.specVersion != null )
                         {
-                            String v = "1.0";
+                            String v = Constants.COMPONENT_DS_SPEC_VERSION_10;
                             if ( comp.getSpecVersion() == Constants.VERSION_1_1 )
                             {
-                                v = "1.1";
+                                v = Constants.COMPONENT_DS_SPEC_VERSION_11;
                             }
                             iLog.addError( "Component " + comp + " requires spec version " + v
                                 + " but plugin is configured to use version " + this.specVersion );
@@ -568,6 +562,7 @@
      * @param component
      */
     protected OCD doComponent( JavaTag tag, Component component, MetaData metaData, final IssueLog iLog )
+        throws SCRDescriptorException
     {
 
         // check if this is an abstract definition
@@ -592,6 +587,13 @@
         component.setEnabled( Boolean.valueOf( getBoolean( tag, Constants.COMPONENT_ENABLED, true ) ) );
         component.setFactory( tag.getNamedParameter( Constants.COMPONENT_FACTORY ) );
 
+        // FELIX-1703: support explicit SCR version declaration
+        final String dsSpecVersion = tag.getNamedParameter( Constants.COMPONENT_DS_SPEC_VERSION );
+        if ( dsSpecVersion != null )
+        {
+            component.setSpecVersion( toSpecVersionCode( dsSpecVersion ) );
+        }
+
         // FELIX-593: immediate attribute does not default to true all the
         // times hence we only set it if declared in the tag
         if ( tag.getNamedParameter( Constants.COMPONENT_IMMEDIATE ) != null )
@@ -946,4 +948,36 @@
             log.error( errors.next() );
         }
     }
+
+    /**
+     * Converts the specification version string to a specification version
+     * code. Currently the following conversions are supported:
+     * <table>
+     * <tr><td><code>null</code></td><td>0</td></tr>
+     * <tr><td>1.0</td><td>0</td></tr>
+     * <tr><td>1.1</td><td>1</td></tr>
+     * </table>
+     *
+     * @param specVersion The specification version to convert. This may be
+     *      <code>null</code> to assume the default version.
+     *
+     * @return The specification version code.
+     *
+     * @throws SCRDescriptorException if the <code>specVersion</code> parameter
+     *      is not a supported value.
+     */
+    private int toSpecVersionCode( String specVersion ) throws SCRDescriptorException
+    {
+        if ( specVersion == null || specVersion.equals( Constants.COMPONENT_DS_SPEC_VERSION_10 ) )
+        {
+            return Constants.VERSION_1_0;
+        }
+        else if ( specVersion.equals( Constants.COMPONENT_DS_SPEC_VERSION_11 ) )
+        {
+            return Constants.VERSION_1_1;
+        }
+
+        // unknown specVersion string
+        throw new SCRDescriptorException( "Unknown configuration for spec version: " + specVersion );
+    }
 }