diff --git a/oak-core-spi/src/main/java/org/apache/jackrabbit/oak/spi/toggle/Feature.java b/oak-core-spi/src/main/java/org/apache/jackrabbit/oak/spi/toggle/Feature.java index afad73f2e6f..7fdc1d2d06d 100644 --- a/oak-core-spi/src/main/java/org/apache/jackrabbit/oak/spi/toggle/Feature.java +++ b/oak-core-spi/src/main/java/org/apache/jackrabbit/oak/spi/toggle/Feature.java @@ -22,8 +22,11 @@ import java.util.Collections; import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.jackrabbit.oak.commons.properties.SystemPropertySupplier; import org.apache.jackrabbit.oak.spi.whiteboard.Registration; import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * A feature toggle to control new functionality. The default state of a feature @@ -34,12 +37,20 @@ * involves registering a feature toggle on the {@link Whiteboard} and * potentially comes with some overhead (e.g. when the whiteboard is based on * OSGi). Therefore, client code should not create a new feature, check the - * state and then immediately release/close it again. Instead a feature should + * state and then immediately release/close it again. Instead, a feature should * be acquired initially, checked at runtime whenever needed and finally * released when the client component is destroyed. + *
+ * The default state of {@code false} can be overridden by a system property
+ * using {@linkplain #newFeatureWithSystemPropertyDefault(String, Whiteboard)},
+ * in which case The property name is derived from the toggle name. This helps to quickly verify
+ * a new feature. For a toggle named {@code "foo"}, the system property name is
+ * {@code oak-feature.foo}.
*/
public final class Feature implements Closeable {
+ private static final Logger LOG = LoggerFactory.getLogger(Feature.class);
+
private final AtomicBoolean value;
private final Registration registration;
@@ -49,6 +60,16 @@ private Feature(AtomicBoolean value, Registration registration) {
this.registration = registration;
}
+ private static Feature internalNewFeatureWithSystemPropertyDefault(String name, Whiteboard whiteboard, boolean withSysPropDefault) {
+ // by default the initial value is false, but it can be overridden by a system property
+ AtomicBoolean value = withSysPropDefault ? new AtomicBoolean(
+ SystemPropertySupplier.create("oak-feature." + name, false).
+ loggingTo(LOG).get()) : new AtomicBoolean();
+ FeatureToggle adapter = new FeatureToggle(name, value);
+ return new Feature(value, whiteboard.register(
+ FeatureToggle.class, adapter, Collections.emptyMap()));
+ }
+
/**
* Creates a new {@link Feature} with the given name and registers the
* corresponding {@link FeatureToggle} on the {@link Whiteboard}.
@@ -60,10 +81,15 @@ private Feature(AtomicBoolean value, Registration registration) {
* @return the feature toggle.
*/
public static Feature newFeature(String name, Whiteboard whiteboard) {
- AtomicBoolean value = new AtomicBoolean();
- FeatureToggle adapter = new FeatureToggle(name, value);
- return new Feature(value, whiteboard.register(
- FeatureToggle.class, adapter, Collections.emptyMap()));
+ return internalNewFeatureWithSystemPropertyDefault(name, whiteboard, false);
+ }
+
+ /**
+ * Same as {@linkplain #newFeature(String, Whiteboard)}, but with the initial state provided
+ * by a system property, named based on the feature's name.
+ */
+ public static Feature newFeatureWithSystemPropertyDefault(String name, Whiteboard whiteboard) {
+ return internalNewFeatureWithSystemPropertyDefault(name, whiteboard, true);
}
/**
diff --git a/oak-core-spi/src/main/java/org/apache/jackrabbit/oak/spi/toggle/package-info.java b/oak-core-spi/src/main/java/org/apache/jackrabbit/oak/spi/toggle/package-info.java
index 840e64c3fcb..c1a3042e113 100644
--- a/oak-core-spi/src/main/java/org/apache/jackrabbit/oak/spi/toggle/package-info.java
+++ b/oak-core-spi/src/main/java/org/apache/jackrabbit/oak/spi/toggle/package-info.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-@Version("1.0.0")
+@Version("1.1.0")
package org.apache.jackrabbit.oak.spi.toggle;
import org.osgi.annotation.versioning.Version;
\ No newline at end of file
diff --git a/oak-core-spi/src/test/java/org/apache/jackrabbit/oak/spi/toggle/FeatureToggleTest.java b/oak-core-spi/src/test/java/org/apache/jackrabbit/oak/spi/toggle/FeatureToggleTest.java
index 7999b04f521..8ffbe3990ca 100644
--- a/oak-core-spi/src/test/java/org/apache/jackrabbit/oak/spi/toggle/FeatureToggleTest.java
+++ b/oak-core-spi/src/test/java/org/apache/jackrabbit/oak/spi/toggle/FeatureToggleTest.java
@@ -28,6 +28,7 @@
import org.junit.Test;
import static org.apache.jackrabbit.oak.spi.toggle.Feature.newFeature;
+import static org.apache.jackrabbit.oak.spi.toggle.Feature.newFeatureWithSystemPropertyDefault;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.core.Is.is;
@@ -50,6 +51,28 @@ public void disabledByDefault() {
}
}
+ @Test
+ public void defaultOverriddenAsTrue() {
+ String sysPropName = "oak-feature.my.toggle";
+ System.setProperty(sysPropName, "true");
+ try (Feature feature = newFeatureWithSystemPropertyDefault("my.toggle", whiteboard)) {
+ assertTrue(feature.isEnabled());
+ } finally {
+ System.clearProperty(sysPropName);
+ }
+ }
+
+ @Test
+ public void defaultOverriddenAsFalse() {
+ String sysPropName = "oak-feature.my.toggle";
+ System.setProperty(sysPropName, "false");
+ try (Feature feature = newFeatureWithSystemPropertyDefault("my.toggle", whiteboard)) {
+ assertFalse(feature.isEnabled());
+ } finally {
+ System.clearProperty(sysPropName);
+ }
+ }
+
@Test
public void register() {
try (Feature feature = newFeature("my.toggle", whiteboard)) {
diff --git a/oak-core-spi/src/test/resources/logback-test.xml b/oak-core-spi/src/test/resources/logback-test.xml
index 042856c27b8..accccfcb4a0 100644
--- a/oak-core-spi/src/test/resources/logback-test.xml
+++ b/oak-core-spi/src/test/resources/logback-test.xml
@@ -34,4 +34,5 @@