Add new enforce-on and since attributes for osgi configurations

SLING-10577
diff --git a/docs/api-regions.md b/docs/api-regions.md
index c8324f0..106162d 100644
--- a/docs/api-regions.md
+++ b/docs/api-regions.md
@@ -148,7 +148,7 @@
      ]
 ```
 
-The deprecation informnation can just be the message, or it can also include information when the deprecated started (since) and by when the member is expected to be removed (for-removal). The removal information should be either the string `true` or a date in the format `YYYY-MM-DD`.
+The deprecation information can just be the message, or it can also include information when the deprecated started (since) and by when the member is expected to be removed (for-removal). The removal information should be either the string `true` or a date in the format `YYYY-MM-DD`.
 
 ## OSGi Configurations
 
@@ -189,6 +189,8 @@
 * `description` : A human readable description
 * `properties` : An object containing all properties that are allowed to be configured
 * `deprecated` : If this configuration should not be used anymore a human readable message.
+* `since` : Info about when the configuration restriction started. It will be appended at the end of every validation message.
+* `enforce-on` : Info about by when the configuration restriction is expected to be enforced (enforced-on). It will be appended at the end of every validation message.
 * `mode` : Validation mode for the configuration overriding the global one. This mode applies to all properties.
 * `region` : Optional property to restrict the configuration to the internal region if this is set to "INTERNAL". With this set, configurations for the internal region can be validated.
 * `allow-additional-properties` : Optional property. If set to true, additional properties not listed in the description are allowed.
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/DescribableEntity.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/DescribableEntity.java
index 9172515..a2bf0eb 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/DescribableEntity.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/DescribableEntity.java
@@ -39,6 +39,18 @@
 	private String deprecated;
 
 	/**
+	 * Optional since information.
+	 * @since 1.3.6
+	 */
+	private String since;
+
+	/**
+	 * Optional enforce on information.
+	 * @since 1.3.6
+	 */
+	private String enforceOn;
+
+	/**
      * Clear the object and reset to defaults
      */
     @Override
@@ -47,6 +59,8 @@
 		this.setTitle(null);
 		this.setDescription(null);
 		this.setDeprecated(null);
+		this.setSince(null);
+		this.setEnforceOn(null);
 	}
 	
 	/**
@@ -63,6 +77,8 @@
 			this.setTitle(this.getString(InternalConstants.KEY_TITLE));
 			this.setDescription(this.getString(InternalConstants.KEY_DESCRIPTION));
 			this.setDeprecated(this.getString(InternalConstants.KEY_DEPRECATED));
+			this.setSince(this.getString(InternalConstants.KEY_SINCE));
+			this.setEnforceOn(this.getString(InternalConstants.KEY_ENFORCE_ON));
         } catch (final JsonException | IllegalArgumentException e) {
             throw new IOException(e);
 		}
@@ -117,6 +133,39 @@
 	}
 
 	/**
+	 * Get the optional since information
+	 * @return The since information or {@code null}
+	 */
+	public String getSince() {
+		return since;
+	}
+
+	/**
+	 * Set the since information. This should a date in the format 'YYYY-MM-DD'.
+	 * @param since The new info
+	 */
+	public void setSince(final String since) {
+		this.since = since;
+	}
+
+
+	/**
+	 * Get the optional since information
+	 * @return The since information or {@code null}
+	 */
+	public String getEnforceOn() {
+		return enforceOn;
+	}
+
+	/**
+	 * Set the enforce on information.
+	 * @param enforceOn The new info
+	 */
+	public void setEnforceOn(final String enforceOn) {
+		this.enforceOn = enforceOn;
+	}
+
+	/**
      * Convert this object into JSON
      *
      * @return The json object builder
@@ -129,6 +178,8 @@
 		this.setString(objectBuilder, InternalConstants.KEY_TITLE, this.getTitle());
 		this.setString(objectBuilder, InternalConstants.KEY_DESCRIPTION, this.getDescription());
 		this.setString(objectBuilder, InternalConstants.KEY_DEPRECATED, this.getDeprecated());
+		this.setString(objectBuilder, InternalConstants.KEY_SINCE, this.getSince());
+		this.setString(objectBuilder, InternalConstants.KEY_ENFORCE_ON, this.getEnforceOn());
 
 		return objectBuilder;
 	}
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/InternalConstants.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/InternalConstants.java
index 7fe12df..b2b9cf7 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/InternalConstants.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/InternalConstants.java
@@ -26,6 +26,10 @@
 	static final String KEY_DESCRIPTION = "description";
 
 	static final String KEY_DEPRECATED = "deprecated";
+
+    static final String KEY_SINCE = "since";
+
+    static final String KEY_ENFORCE_ON = "enforce-on";
 	
 	static final String KEY_PROPERTIES = "properties";
 
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/package-info.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/package-info.java
index ac5f0b1..49fdfc7 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/package-info.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/package-info.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-@org.osgi.annotation.versioning.Version("1.4.0")
+@org.osgi.annotation.versioning.Version("1.5.0")
 package org.apache.sling.feature.extension.apiregions.api.config;
 
 
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidator.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidator.java
index 2eb7080..6c21962 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidator.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidator.java
@@ -137,6 +137,22 @@
         if ( desc.getDeprecated() != null ) {
             result.getWarnings().add(desc.getDeprecated());
         }
+
+        // set postfix to the message if since or enforce-on are set
+        String postfixMsg = "";
+        if ( desc.getSince() != null ) {
+            postfixMsg = postfixMsg.concat(". Since : ").concat(desc.getSince());
+        }
+        if ( desc.getEnforceOn() != null ) {
+            postfixMsg = postfixMsg.concat(". Enforced on : ").concat(desc.getEnforceOn());
+        }
+        for (int i = 0; i < result.getWarnings().size(); i++) {
+            result.getWarnings().set(i, result.getWarnings().get(i) + postfixMsg);
+        }
+        for (int i = 0; i < result.getErrors().size(); i++) {
+            result.getErrors().set(i, result.getErrors().get(i) + postfixMsg);
+        }
+
         return result;
     }
 
@@ -212,4 +228,4 @@
     void setCache(Map<ArtifactId, Region> cache) {
         this.cache = cache;
     }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidator.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidator.java
index e881ba2..f85a2ff 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidator.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidator.java
@@ -118,6 +118,21 @@
             if ( desc.getDeprecated() != null ) {
                 context.result.getWarnings().add(desc.getDeprecated());
             }
+
+            // set postfix to the message if since or enforce-on are set
+            String postfixMsg = "";
+            if ( desc.getSince() != null ) {
+                postfixMsg = postfixMsg.concat(". Since : ").concat(desc.getSince());
+            }
+            if ( desc.getEnforceOn() != null ) {
+                postfixMsg = postfixMsg.concat(". Enforced on : ").concat(desc.getEnforceOn());
+            }
+            for (int i = 0; i < context.result.getWarnings().size(); i++) {
+                context.result.getWarnings().set(i, context.result.getWarnings().get(i) + postfixMsg);
+            }
+            for (int i = 0; i < context.result.getErrors().size(); i++) {
+                context.result.getErrors().set(i, context.result.getErrors().get(i) + postfixMsg);
+            }
 		}
 		return context.result;
 	}
diff --git a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/DescribableEntityTest.java b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/DescribableEntityTest.java
index f2ad633..9293a85 100644
--- a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/DescribableEntityTest.java
+++ b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/DescribableEntityTest.java
@@ -41,16 +41,21 @@
         entity.setDeprecated("d");
         entity.setTitle("t");
         entity.setDescription("x");
+        entity.setEnforceOn("e");
+        entity.setSince("s");
         entity.clear();
         assertTrue(entity.getAttributes().isEmpty());
         assertNull(entity.getDeprecated());
         assertNull(entity.getTitle());
         assertNull(entity.getDescription());
+        assertNull(entity.getEnforceOn());
+        assertNull(entity.getSince());
     }
 
     @Test public void testFromJSONObject() throws IOException {
         final Extension ext = new Extension(ExtensionType.JSON, "a", ExtensionState.OPTIONAL);
-        ext.setJSON("{ \"a\" : 1, \"b\" : \"2\", \"title\" : \"t\", \"description\" : \"desc\", \"deprecated\" : \"depr\"}");
+        ext.setJSON("{ \"a\" : 1, \"b\" : \"2\", \"title\" : \"t\", \"description\" : \"desc\", \"deprecated\" : " +
+                "\"depr\", \"enforce-on\" : \"1970-04-01\", \"since\" : \"1970-01-01\"}");
 
         final DE entity = new DE();
         entity.fromJSONObject(ext.getJSONStructure().asJsonObject());
@@ -59,7 +64,8 @@
         assertEquals(Json.createValue("2"), entity.getAttributes().get("b"));
         assertEquals("t", entity.getTitle());
         assertEquals("desc", entity.getDescription());
-        assertEquals("depr", entity.getDeprecated());
+        assertEquals("1970-04-01", entity.getEnforceOn());
+        assertEquals("1970-01-01", entity.getSince());
     }
 
     @Test public void testToJSONObject() throws IOException {
@@ -69,10 +75,13 @@
         entity.setTitle("t");
         entity.setDescription("desc");
         entity.setDeprecated("depr");
+        entity.setEnforceOn("1970-04-01");
+        entity.setSince("1970-01-01");
 
         final Extension ext = new Extension(ExtensionType.JSON, "a", ExtensionState.OPTIONAL);
-        ext.setJSON("{ \"a\" : 1, \"b\" : \"2\", \"title\" : \"t\", \"description\" : \"desc\", \"deprecated\" : \"depr\"}");
+        ext.setJSON("{ \"a\" : 1, \"b\" : \"2\", \"title\" : \"t\", \"description\" : \"desc\", \"deprecated\" : " +
+                "\"depr\", \"enforce-on\" : \"1970-04-01\", \"since\" : \"1970-01-01\"}");
 
         assertEquals(ext.getJSONStructure().asJsonObject(), entity.toJSONObject());
     }
-}
\ No newline at end of file
+}
diff --git a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidatorTest.java b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidatorTest.java
index 1cfff34..7628582 100644
--- a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidatorTest.java
+++ b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/ConfigurationValidatorTest.java
@@ -69,6 +69,26 @@
         assertEquals("this is deprecated", result.getWarnings().get(0));
     }
 
+    @Test public void testMessageWithEnforceAndSinceInfo() {
+        final Configuration cfg = new Configuration("org.apache");
+        final ConfigurationDescription cd = new ConfigurationDescription();
+        final PropertyDescription prop = new PropertyDescription();
+        cd.getPropertyDescriptions().put("a", prop);
+
+        ConfigurationValidationResult result = validator.validate(cfg, cd, null);
+        assertTrue(result.isValid());
+        assertTrue(result.getWarnings().isEmpty());
+
+        cd.setDeprecated("this is deprecated");
+        cd.setSince("1970-01-01");
+        cd.setEnforceOn("1970-04-01");
+        result = validator.validate(cfg, cd, null);
+        assertTrue(result.isValid());
+        assertFalse(result.getWarnings().isEmpty());
+        assertEquals("this is deprecated. Since : 1970-01-01. Enforced on : 1970-04-01",
+                result.getWarnings().get(0));
+    }
+
     @Test public void testServiceRanking() {
         final Configuration cfg = new Configuration("org.apache");
         final ConfigurationDescription cd = new ConfigurationDescription();
diff --git a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidatorTest.java b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidatorTest.java
index 29fc3cc..7411375 100644
--- a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidatorTest.java
+++ b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/PropertyValidatorTest.java
@@ -425,6 +425,19 @@
         assertEquals("This is deprecated", result.getWarnings().get(0));
     }
 
+
+    @Test public void testEnforceOnAndSinceInMsg() {
+        final PropertyDescription prop = new PropertyDescription();
+        prop.setDeprecated("Deprecated message");
+        prop.setEnforceOn("1970-04-01");
+        prop.setSince("1970-01-01");
+
+        final PropertyValidationResult result = validator.validate("foo", prop);
+        assertTrue(result.isValid());
+        assertEquals(1, result.getWarnings().size());
+        assertEquals("Deprecated message. Since : 1970-01-01. Enforced on : 1970-04-01", result.getWarnings().get(0));
+    }
+
     @Test public void testPlaceholdersString() {
         final PropertyDescription desc = new PropertyDescription();
         desc.setType(PropertyType.PATH);