SLING-10473 : Provide a way to disable placeholder check
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 b73022a..5dd16c0 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
@@ -46,6 +46,27 @@
 
     private final PropertyValidator propertyValidator = new PropertyValidator();
 
+    private boolean liveValues = false;
+
+    /**
+     * Are live values validated?
+     * @return {@code true} if live values are validated
+     * @since 1.4
+     */
+    public boolean isLiveValues() {
+        return liveValues;
+    }
+
+    /**
+     * Set whether live values are validated.
+     * @param value Flag for validating live values
+     * @since 1.4
+     */
+    public void setLiveValues(final boolean value) {
+        this.liveValues = value;
+        this.propertyValidator.setLiveValues(value);
+    }
+
     /**
      * Validate a configuration
      * 
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/FeatureValidator.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/FeatureValidator.java
index 7ab6187..7b90df7 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/FeatureValidator.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/FeatureValidator.java
@@ -44,6 +44,8 @@
 
     private FeatureProvider featureProvider;
 
+    private boolean liveValues = false;
+
     /**
      * Get the current feature provider
      * @return the feature provider or {@code null}
@@ -61,6 +63,26 @@
     }
 
     /**
+     * Are live values validated?
+     * @return {@code true} if live values are validated
+     * @since 1.4
+     */
+    public boolean isLiveValues() {
+        return liveValues;
+    }
+
+    /**
+     * Set whether live values are validated.
+     * @param value Flag for validating live values
+     * @since 1.4
+     */
+    public void setLiveValues(final boolean value) {
+        this.liveValues = value;
+        this.configurationValidator.setLiveValues(value);
+        this.propertyValidator.setLiveValues(value);
+    }
+
+    /**
      * Validate the feature against its configuration API
      * @param feature The feature
      * @return A {@code FeatureValidationResult}
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 0e3f5be..728945e 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
@@ -35,6 +35,26 @@
  */
 public class PropertyValidator {
     
+    private boolean liveValues = false;
+
+    /**
+     * Are live values validated?
+     * @return {@code true} if live values are validated
+     * @since 1.4
+     */
+    public boolean isLiveValues() {
+        return liveValues;
+    }
+
+    /**
+     * Set whether live values are validated.
+     * @param value Flag for validating live values
+     * @since 1.4
+     */
+    public void setLiveValues(final boolean value) {
+        this.liveValues = value;
+    }
+
 	/**
 	 * Validate the value against the property definition
      * @param value The value to validate
@@ -388,7 +408,7 @@
 	}
 
 	void validatePassword(final Context context, final Object value, final boolean hasPlaceholder) {
-        if ( !hasPlaceholder && context.description.getPlaceholderPolicy() != PlaceholderPolicy.DENY ) {
+        if ( !this.isLiveValues() && !hasPlaceholder && context.description.getPlaceholderPolicy() != PlaceholderPolicy.DENY ) {
             setResult(context, "Value for a password must use a placeholder");
         }
 	}
@@ -455,12 +475,15 @@
     }
 
     void validatePlaceholderPolicy(final Context context, final Object value, final boolean hasPlaceholder) {
-        // for policy default and allow nothing needs to be validated
-        if ( context.description.getPlaceholderPolicy() == PlaceholderPolicy.DENY && hasPlaceholder ) {
-            setResult(context, "Placeholder in value is not allowed");
-        }  else if ( context.description.getPlaceholderPolicy() == PlaceholderPolicy.REQUIRE && !hasPlaceholder ) {
-            setResult(context, "Value must use a placeholder");
-        }
+        // only check policy if no live values
+        if ( !this.isLiveValues() ) {
+            // for policy default and allow nothing needs to be validated
+            if ( context.description.getPlaceholderPolicy() == PlaceholderPolicy.DENY && hasPlaceholder ) {
+                setResult(context, "Placeholder in value is not allowed");
+            }  else if ( context.description.getPlaceholderPolicy() == PlaceholderPolicy.REQUIRE && !hasPlaceholder ) {
+                setResult(context, "Value must use a placeholder");
+            }
+        } 
     }         
 
     static final class Context {
diff --git a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/package-info.java b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/package-info.java
index 332f38d..0c81064 100644
--- a/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/package-info.java
+++ b/src/main/java/org/apache/sling/feature/extension/apiregions/api/config/validation/package-info.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-@org.osgi.annotation.versioning.Version("1.3.0")
+@org.osgi.annotation.versioning.Version("1.4.0")
 package org.apache.sling.feature.extension.apiregions.api.config.validation;
 
 
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 b233ee0..2d7d697 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
@@ -260,4 +260,9 @@
         assertTrue(result.getPropertyResults().isEmpty());
         assertTrue(result.getErrors().isEmpty());
     }
+
+    @Test
+    public void testLiveValidation() {
+        assertFalse(this.validator.isLiveValues());
+    }
 }
diff --git a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/FeatureValidatorTest.java b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/FeatureValidatorTest.java
index 09bc337..483d67f 100644
--- a/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/FeatureValidatorTest.java
+++ b/src/test/java/org/apache/sling/feature/extension/apiregions/api/config/validation/FeatureValidatorTest.java
@@ -936,4 +936,28 @@
         validator.applyDefaultValues(f1, result);
         assertEquals(0, f1.getConfigurations().getConfiguration(FACTORY_PID.concat("~print")).getConfigurationProperties().size());
     }
+
+    @Test
+    public void testLiveValidation() {
+        assertFalse(validator.isLiveValues());
+        
+        final Feature feature = createFeature("g:a:1");
+        final ConfigurationApi api = createApi();
+        // make property a password requiring a placeholder
+        api.getConfigurationDescriptions().get(PID).getPropertyDescriptions().get("prop").setType(PropertyType.PASSWORD);
+
+        // validate non live values - this should value as no secret is used for the password
+        FeatureValidationResult result = validator.validate(feature, api);
+        assertFalse(result.isValid());
+
+        try {
+            validator.setLiveValues(true);
+
+            result = validator.validate(feature, api);
+            assertTrue(result.isValid());
+    
+        } finally {
+            validator.setLiveValues(false);
+        }
+    }
 }
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 2ad6fab..e3a8333 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
@@ -508,4 +508,30 @@
         assertTrue(result.isValid());
         assertFalse(result.isSkipped());
     }
+
+
+    @Test
+    public void testLiveValidation() {
+        assertFalse(this.validator.isLiveValues());
+
+        try {
+            this.validator.setLiveValues(true);
+
+            final PropertyDescription desc = new PropertyDescription();
+            desc.setPlaceholderPolicy(PlaceholderPolicy.DENY);
+    
+            PropertyValidationResult result = null;
+    
+            result = validator.validate("$[env:variable]", desc);
+            assertTrue(result.isValid());
+            assertFalse(result.isSkipped());
+    
+            result = validator.validate("hello", desc);
+            assertTrue(result.isValid());
+            assertFalse(result.isSkipped());
+
+        } finally {
+            this.validator.setLiveValues(false);
+        }
+    }
 }
\ No newline at end of file