FELIX-3552 : Implement new features of DS 1.2

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1350296 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/ConfigurationPolicy.java b/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/ConfigurationPolicy.java
index 871cebe..9525257 100644
--- a/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/ConfigurationPolicy.java
+++ b/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/ConfigurationPolicy.java
@@ -38,12 +38,4 @@
      * In order to activate this component a configuration is required.
      */
     REQUIRE;
-
-    /**
-     * @return String representation of policy
-     */
-    public String getPolicyString() {
-        return this.name().toLowerCase();
-    }
-
 }
diff --git a/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/Reference.java b/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/Reference.java
index 1dd1201..affc26c 100644
--- a/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/Reference.java
+++ b/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/Reference.java
@@ -18,7 +18,11 @@
  */
 package org.apache.felix.scr.annotations;
 
-import java.lang.annotation.*;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 /**
  * The <code>Reference</code> annotation defines references to other services
@@ -68,6 +72,12 @@
     ReferencePolicy policy() default ReferencePolicy.STATIC;
 
     /**
+     * The policy option for the reference
+     * @since 1.7
+     */
+    ReferencePolicyOption policyOption() default ReferencePolicyOption.RELUCTANT;
+
+    /**
      * A service target filter to select specific services to be made available.
      * In order to be able to overwrite the value of this value by a
      * configuration property, this parameter must be declared. If the parameter
diff --git a/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/ReferencePolicy.java b/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/ReferencePolicy.java
index e476fa4..00ceaad 100644
--- a/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/ReferencePolicy.java
+++ b/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/ReferencePolicy.java
@@ -33,12 +33,4 @@
      * The service will be made available to the component as it comes and goes.
      */
     DYNAMIC;
-
-    /**
-     * @return String representation of policy
-     */
-    public String getPolicyString() {
-        return this.name().toLowerCase();
-    }
-
 }
diff --git a/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/ReferencePolicyOption.java b/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/ReferencePolicyOption.java
new file mode 100644
index 0000000..a79fd8a
--- /dev/null
+++ b/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/ReferencePolicyOption.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.scr.annotations;
+
+/**
+ * Options for {@link Reference#policyOption()} property.
+ */
+public enum ReferencePolicyOption {
+
+    /**
+     * The reluctant policy option is the default policy option.
+     * When a new target service for a reference becomes available,
+     * references having the reluctant policy option for the static
+     * policy or the dynamic policy with a unary cardinality will
+     * ignore the new target service. References having the dynamic
+     * policy with a multiple cardinality will bind the new
+     * target service
+     */
+    RELUCTANT,
+
+    /**
+     * When a new target service for a reference becomes available,
+     * references having the greedy policy option will bind the new
+     * target service.
+     */
+    GREEDY;
+}
diff --git a/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/ReferenceStrategy.java b/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/ReferenceStrategy.java
index 4193781..4b2888c 100644
--- a/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/ReferenceStrategy.java
+++ b/scrplugin/annotations/src/main/java/org/apache/felix/scr/annotations/ReferenceStrategy.java
@@ -26,12 +26,4 @@
     EVENT,
 
     LOOKUP;
-
-    /**
-     * @return String representation of the stragey
-     */
-    public String getStrategyString() {
-        return this.name().toLowerCase();
-    }
-
 }
diff --git a/scrplugin/annotations/src/main/java/org/apache/felix/scrplugin/processing/SCRAnnotationProcessor.java b/scrplugin/annotations/src/main/java/org/apache/felix/scrplugin/processing/SCRAnnotationProcessor.java
index f1cd0fa..6060330 100644
--- a/scrplugin/annotations/src/main/java/org/apache/felix/scrplugin/processing/SCRAnnotationProcessor.java
+++ b/scrplugin/annotations/src/main/java/org/apache/felix/scrplugin/processing/SCRAnnotationProcessor.java
@@ -53,6 +53,7 @@
 import org.apache.felix.scrplugin.description.ReferenceCardinality;
 import org.apache.felix.scrplugin.description.ReferenceDescription;
 import org.apache.felix.scrplugin.description.ReferencePolicy;
+import org.apache.felix.scrplugin.description.ReferencePolicyOption;
 import org.apache.felix.scrplugin.description.ReferenceStrategy;
 import org.apache.felix.scrplugin.description.ServiceDescription;
 
@@ -304,6 +305,7 @@
             ref.setCardinality(ReferenceCardinality.valueOf(ad.getEnumValue("cardinality",
                             ReferenceCardinality.MANDATORY_UNARY.name())));
             ref.setPolicy(ReferencePolicy.valueOf(ad.getEnumValue("policy", ReferencePolicy.STATIC.name())));
+            ref.setPolicyOption(ReferencePolicyOption.valueOf(ad.getEnumValue("policyOption", ReferencePolicyOption.RELUCTANT.name())));
             ref.setStrategy(ReferenceStrategy.valueOf(ad.getEnumValue("strategy", ReferenceStrategy.EVENT.name())));
 
             ref.setBind(getMethodDescription(ad.getStringValue("bind", null)));
diff --git a/scrplugin/ds-annotations/src/main/java/org/apache/felix/scrplugin/ds/DSAnnotationProcessor.java b/scrplugin/ds-annotations/src/main/java/org/apache/felix/scrplugin/ds/DSAnnotationProcessor.java
index 0369498..2ce7c11 100644
--- a/scrplugin/ds-annotations/src/main/java/org/apache/felix/scrplugin/ds/DSAnnotationProcessor.java
+++ b/scrplugin/ds-annotations/src/main/java/org/apache/felix/scrplugin/ds/DSAnnotationProcessor.java
@@ -40,6 +40,7 @@
 import org.apache.felix.scrplugin.description.ReferenceCardinality;
 import org.apache.felix.scrplugin.description.ReferenceDescription;
 import org.apache.felix.scrplugin.description.ReferencePolicy;
+import org.apache.felix.scrplugin.description.ReferencePolicyOption;
 import org.apache.felix.scrplugin.description.ReferenceStrategy;
 import org.apache.felix.scrplugin.description.ServiceDescription;
 import org.osgi.service.component.annotations.Activate;
@@ -284,6 +285,8 @@
 
         // policy
         ref.setPolicy(ReferencePolicy.valueOf(ad.getEnumValue("policy", ReferencePolicy.STATIC.name())));
+        // policy option
+        ref.setPolicyOption(ReferencePolicyOption.valueOf(ad.getEnumValue("policyOption", ReferencePolicyOption.RELUCTANT.name())));
         // target
         ref.setTarget(ad.getStringValue("target", null));
     }
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 f877206..067eff9 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
@@ -34,6 +34,7 @@
 import org.apache.felix.scrplugin.description.PropertyUnbounded;
 import org.apache.felix.scrplugin.description.ReferenceCardinality;
 import org.apache.felix.scrplugin.description.ReferenceDescription;
+import org.apache.felix.scrplugin.description.ReferencePolicyOption;
 import org.apache.felix.scrplugin.description.ServiceDescription;
 import org.apache.felix.scrplugin.helper.AnnotationProcessorManager;
 import org.apache.felix.scrplugin.helper.ClassModifier;
@@ -651,6 +652,10 @@
             ref.setStrategy(rd.getStrategy());
             ref.setTarget(rd.getTarget());
             ref.setField(rd.getField());
+            ref.setPolicyOption(rd.getPolicyOption());
+            if ( ref.getPolicyOption() != ReferencePolicyOption.RELUCTANT ) {
+                component.setSpecVersion(SpecVersion.VERSION_1_2);
+            }
             if ( rd.getBind() != null ) {
                 ref.setBind(rd.getBind().getName());
             }
@@ -658,8 +663,11 @@
                 ref.setUnbind(rd.getUnbind().getName());
             }
             if ( rd.getUpdated() != null ) {
-                // updated requires 1.2
-                component.setSpecVersion(SpecVersion.VERSION_1_2);
+                // updated requires 1.2 or 1.1_FELIX, if nothing is set, we use 1.2
+                if ( component.getSpecVersion() == null
+                     || component.getSpecVersion().ordinal() < SpecVersion.VERSION_1_1_FELIX.ordinal() ) {
+                    component.setSpecVersion(SpecVersion.VERSION_1_2);
+                }
                 ref.setUpdated(rd.getUpdated().getName());
             }
 
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 b7c18eb..57fb7d8 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
@@ -34,6 +34,7 @@
  * <li>target</li>
  * <li>cardinality</li>
  * <li>policy</li>
+ * <li>policyOption</li>
  * <li>strategy</li>
  * </ul>
  *
@@ -52,6 +53,7 @@
     private String target;
     private ReferenceCardinality cardinality;
     private ReferencePolicy policy;
+    private ReferencePolicyOption policyOption;
     private ReferenceStrategy strategy;
 
     private Field field;
@@ -104,6 +106,14 @@
         this.policy = policy;
     }
 
+    public ReferencePolicyOption getPolicyOption() {
+        return policyOption;
+    }
+
+    public void setPolicyOption(ReferencePolicyOption policyOption) {
+        this.policyOption = policyOption;
+    }
+
     public MethodDescription getBind() {
         return bind;
     }
@@ -140,7 +150,8 @@
     public String toString() {
         return "ReferenceDescription [name=" + name + ", interfaceName="
                 + interfaceName + ", target=" + target + ", cardinality="
-                + cardinality + ", policy=" + policy + ", bind=" + bind
+                + cardinality + ", policy=" + policy + ", policyOption=" + policyOption +
+                "bind=" + bind
                 + ", unbind=" + unbind + ", updated=" + updated + ", strategy="
                 + strategy + ", field=" + field + ", annotation=" + annotation
                 + "]";
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ReferencePolicyOption.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ReferencePolicyOption.java
new file mode 100644
index 0000000..6663611
--- /dev/null
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/description/ReferencePolicyOption.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.scrplugin.description;
+
+/**
+ * Options for {@link ReferenceDescription#getPolicyOption()} property.
+ */
+public enum ReferencePolicyOption {
+
+    /**
+     * The reluctant policy option is the default policy option.
+     * When a new target service for a reference becomes available,
+     * references having the reluctant policy option for the static
+     * policy or the dynamic policy with a unary cardinality will
+     * ignore the new target service. References having the dynamic
+     * policy with a multiple cardinality will bind the new
+     * target service
+     */
+    RELUCTANT,
+
+    /**
+     * When a new target service for a reference becomes available,
+     * references having the greedy policy option will bind the new
+     * target service.
+     */
+    GREEDY;
+}
diff --git a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/om/Reference.java b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/om/Reference.java
index ee932e3..fc0aab7 100644
--- a/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/om/Reference.java
+++ b/scrplugin/generator/src/main/java/org/apache/felix/scrplugin/om/Reference.java
@@ -28,6 +28,7 @@
 import org.apache.felix.scrplugin.annotations.ScannedAnnotation;
 import org.apache.felix.scrplugin.description.ReferenceCardinality;
 import org.apache.felix.scrplugin.description.ReferencePolicy;
+import org.apache.felix.scrplugin.description.ReferencePolicyOption;
 import org.apache.felix.scrplugin.description.ReferenceStrategy;
 import org.apache.felix.scrplugin.helper.StringUtils;
 
@@ -42,6 +43,7 @@
     protected String target;
     protected ReferenceCardinality cardinality;
     protected ReferencePolicy policy;
+    protected ReferencePolicyOption policyOption;
     protected String bind;
     protected String unbind;
     protected String updated;
@@ -106,6 +108,14 @@
         this.policy = policy;
     }
 
+    public ReferencePolicyOption getPolicyOption() {
+        return this.policyOption;
+    }
+
+    public void setPolicyOption(ReferencePolicyOption policyOption) {
+        this.policyOption = policyOption;
+    }
+
     public String getBind() {
         return this.bind;
     }
@@ -181,6 +191,16 @@
             this.policy = ReferencePolicy.STATIC;
         }
 
+        // validate policy option
+        if ( this.policyOption == null ) {
+            this.policyOption = ReferencePolicyOption.RELUCTANT;
+        }
+        if ( this.policyOption != ReferencePolicyOption.RELUCTANT ) {
+            if ( context.getSpecVersion().ordinal() < SpecVersion.VERSION_1_2.ordinal() ) {
+                this.logError(context.getIssueLog(), "ReferencePolicyOption " + this.policyOption.name() +
+                                " requires spec version " + SpecVersion.VERSION_1_2.getName() + " or higher.");
+            }
+        }
         // validate strategy
         if (this.strategy == null) {
             this.strategy = ReferenceStrategy.EVENT;
@@ -225,7 +245,7 @@
         if (this.updated != null) {
             if (context.getSpecVersion().ordinal() < SpecVersion.VERSION_1_1_FELIX.ordinal()) {
                 this.logError(context.getIssueLog(), "Updated method declaration requires version "
-                                + SpecVersion.VERSION_1_1_FELIX.getName() + ", " + SpecVersion.VERSION_1_2 + " or newer");
+                                + SpecVersion.VERSION_1_1_FELIX.getName() + ", " + SpecVersion.VERSION_1_2.getName() + " or newer");
             }
         }
 
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 48c9d94..37bc803 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
@@ -38,6 +38,7 @@
 import org.apache.felix.scrplugin.description.ReferenceCardinality;
 import org.apache.felix.scrplugin.description.ReferenceDescription;
 import org.apache.felix.scrplugin.description.ReferencePolicy;
+import org.apache.felix.scrplugin.description.ReferencePolicyOption;
 import org.apache.felix.scrplugin.description.ReferenceStrategy;
 import org.apache.felix.scrplugin.description.ServiceDescription;
 import org.apache.felix.scrplugin.helper.IssueLog;
@@ -200,7 +201,7 @@
         // attributes new in 1.1
         if (component.getSpecVersion().ordinal() >= SpecVersion.VERSION_1_1.ordinal() ) {
             if ( component.getConfigurationPolicy() != ComponentConfigurationPolicy.OPTIONAL ) {
-                IOUtils.addAttribute(ai, COMPONENT_ATTR_POLICY, component.getConfigurationPolicy().name());
+                IOUtils.addAttribute(ai, COMPONENT_ATTR_POLICY, component.getConfigurationPolicy().name().toLowerCase());
             }
             IOUtils.addAttribute(ai, COMPONENT_ATTR_ACTIVATE, component.getActivate());
             IOUtils.addAttribute(ai, COMPONENT_ATTR_DEACTIVATE, component.getDeactivate());
@@ -334,7 +335,7 @@
         IOUtils.addAttribute(ai, "name", reference.getName());
         IOUtils.addAttribute(ai, "interface", reference.getInterfacename());
         IOUtils.addAttribute(ai, "cardinality", reference.getCardinality().getCardinalityString());
-        IOUtils.addAttribute(ai, "policy", reference.getPolicy().name());
+        IOUtils.addAttribute(ai, "policy", reference.getPolicy().name().toLowerCase());
         IOUtils.addAttribute(ai, "target", reference.getTarget());
         IOUtils.addAttribute(ai, "bind", reference.getBind());
         IOUtils.addAttribute(ai, "unbind", reference.getUnbind());
@@ -344,6 +345,13 @@
             IOUtils.addAttribute(ai, "updated", reference.getUpdated());
         }
 
+        // attributes new in 1.2
+        if (component.getSpecVersion().ordinal() >= SpecVersion.VERSION_1_2.ordinal() ) {
+            if ( reference.getPolicyOption() != ReferencePolicyOption.RELUCTANT ) {
+                IOUtils.addAttribute(ai, "policy-option", reference.getPolicyOption().name().toLowerCase());
+            }
+        }
+
         IOUtils.indent(contentHandler, 2);
         contentHandler.startElement(INNER_NAMESPACE_URI, ComponentDescriptorIO.REFERENCE, ComponentDescriptorIO.REFERENCE_QNAME,
                         ai);
@@ -544,14 +552,24 @@
                             iLog.addWarning("Invalid value for attribute cardinality : " + cardinality, this.location);
                         }
                     }
+                    ref.setPolicy(ReferencePolicy.STATIC);
                     final String policy = attributes.getValue("policy");
                     if ( policy != null ) {
                         try {
-                            ref.setPolicy(ReferencePolicy.valueOf(policy));
+                            ref.setPolicy(ReferencePolicy.valueOf(policy.toUpperCase()));
                         } catch (final IllegalArgumentException iae) {
                             iLog.addWarning("Invalid value for attribute policy : " + policy, this.location);
                         }
                     }
+                    ref.setPolicyOption(ReferencePolicyOption.RELUCTANT);
+                    final String policyOption = attributes.getValue("policy-option");
+                    if ( policyOption != null ) {
+                        try {
+                            ref.setPolicyOption(ReferencePolicyOption.valueOf(policyOption.toUpperCase()));
+                        } catch (final IllegalArgumentException iae) {
+                            iLog.addWarning("Invalid value for attribute policy-option : " + policyOption, this.location);
+                        }
+                    }
                     ref.setTarget(attributes.getValue("target"));
                     if ( attributes.getValue("bind") != null ) {
                         ref.setBind(new MethodDescription(attributes.getValue("bind")));
@@ -563,7 +581,7 @@
                     final String strategy = attributes.getValue("strategy");
                     if ( strategy != null ) {
                         try {
-                            ref.setStrategy(ReferenceStrategy.valueOf(strategy));
+                            ref.setStrategy(ReferenceStrategy.valueOf(strategy.toUpperCase()));
                         } catch (final IllegalArgumentException iae) {
                             throw new SAXException("Invalid value for attribute strategy : " + strategy);
                         }