BOOKKEEPER-941: Feature Switches for controling client and server behavior
- Introduce Features that are dynamic configuration options
- Allow specifying Features as configuration parameters
This is a port of the feature switches following changes
https://github.com/twitter/bookkeeper/commit/c2a092ab9b585f1d30d9e9b9dead0533efa49855
https://github.com/twitter/bookkeeper/commit/f9762d126e311a6b129e6e169dc62c2a0bdb7b4a
Author: Robin Dhamankar <robindh@Robins-MacBook-Air.local>
Reviewers: Matteo Merli <mmerli@apache.org>, Sijie Guo <sijie@apache.org>
Closes #54 from robindh/FeatureSwitches
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/AbstractConfiguration.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/AbstractConfiguration.java
index 314290e..adf08ff 100644
--- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/AbstractConfiguration.java
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/AbstractConfiguration.java
@@ -25,6 +25,7 @@
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.SystemConfiguration;
+import org.apache.bookkeeper.feature.Feature;
import org.apache.bookkeeper.meta.LedgerManagerFactory;
import org.apache.bookkeeper.util.ReflectionUtils;
@@ -243,4 +244,16 @@
public void setMetastoreMaxEntriesPerScan(int maxEntries) {
setProperty(METASTORE_MAX_ENTRIES_PER_SCAN, maxEntries);
}
+
+ public void setFeature(String configProperty, Feature feature) {
+ setProperty(configProperty, feature);
+ }
+
+ public Feature getFeature(String configProperty, Feature defaultValue) {
+ if (null == getProperty(configProperty)) {
+ return defaultValue;
+ } else {
+ return (Feature)getProperty(configProperty);
+ }
+ }
}
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/feature/CacheableFeatureProvider.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/feature/CacheableFeatureProvider.java
new file mode 100644
index 0000000..95c9981
--- /dev/null
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/feature/CacheableFeatureProvider.java
@@ -0,0 +1,85 @@
+package org.apache.bookkeeper.feature;
+
+/*
+ *
+ * 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.
+ *
+ */
+
+import org.apache.commons.lang.StringUtils;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Cacheable Feature Provider
+ */
+public abstract class CacheableFeatureProvider<T extends Feature> implements FeatureProvider {
+
+ protected final String scope;
+ protected final ConcurrentMap<String, FeatureProvider> scopes =
+ new ConcurrentHashMap<String, FeatureProvider>();
+ protected final ConcurrentMap<String, T> features =
+ new ConcurrentHashMap<String, T>();
+
+ protected CacheableFeatureProvider(String scope) {
+ this.scope = scope;
+ }
+
+ protected String makeName(String name) {
+ if (StringUtils.isBlank(scope)) {
+ return name;
+ } else {
+ return scope + "." + name;
+ }
+ }
+
+ @Override
+ public T getFeature(String name) {
+ T feature = features.get(name);
+ if (null == feature) {
+ T newFeature = makeFeature(makeName(name));
+ T oldFeature = features.putIfAbsent(name, newFeature);
+ if (null == oldFeature) {
+ feature = newFeature;
+ } else {
+ feature = oldFeature;
+ }
+ }
+ return feature;
+ }
+
+ protected abstract T makeFeature(String featureName);
+
+ @Override
+ public FeatureProvider scope(String name) {
+ FeatureProvider provider = scopes.get(name);
+ if (null == provider) {
+ FeatureProvider newProvider = makeProvider(makeName(name));
+ FeatureProvider oldProvider = scopes.putIfAbsent(name, newProvider);
+ if (null == oldProvider) {
+ provider = newProvider;
+ } else {
+ provider = oldProvider;
+ }
+ }
+ return provider;
+ }
+
+ protected abstract FeatureProvider makeProvider(String fullScopeName);
+}
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/feature/Feature.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/feature/Feature.java
new file mode 100644
index 0000000..ab9fae9
--- /dev/null
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/feature/Feature.java
@@ -0,0 +1,51 @@
+package org.apache.bookkeeper.feature;
+
+/*
+ *
+ * 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.
+ *
+ */
+
+/**
+ * This interface represents a feature.
+ */
+public interface Feature {
+ public static int FEATURE_AVAILABILITY_MAX_VALUE = 100;
+
+ /**
+ * Returns a textual representation of the feature.
+ *
+ * @return name of the feature.
+ */
+ String name();
+
+ /**
+ * Returns the availability of this feature, an integer between 0 and 100.
+ *
+ * @return the availability of this feature.
+ */
+ int availability();
+
+ /**
+ * Whether this feature is available or not.
+ *
+ * @return true if this feature is available, otherwise false.
+ */
+ boolean isAvailable();
+}
+
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/feature/FeatureProvider.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/feature/FeatureProvider.java
new file mode 100644
index 0000000..04686b7
--- /dev/null
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/feature/FeatureProvider.java
@@ -0,0 +1,44 @@
+package org.apache.bookkeeper.feature;
+
+/*
+ *
+ * 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.
+ *
+ */
+
+/**
+ * Provider to provide features.
+ */
+public interface FeatureProvider {
+ /**
+ * Return the feature with given name.
+ *
+ * @param name feature name
+ * @return feature instance
+ */
+ Feature getFeature(String name);
+
+ /**
+ * Provide the feature provider under scope <i>name</i>.
+ *
+ * @param name
+ * scope name.
+ * @return feature provider under scope <i>name</i>
+ */
+ FeatureProvider scope(String name);
+}
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/feature/FixedValueFeature.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/feature/FixedValueFeature.java
new file mode 100644
index 0000000..825276b
--- /dev/null
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/feature/FixedValueFeature.java
@@ -0,0 +1,52 @@
+package org.apache.bookkeeper.feature;
+
+/*
+ *
+ * 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.
+ *
+ */
+
+public class FixedValueFeature implements Feature {
+ protected final String name;
+ protected int availability;
+
+ public FixedValueFeature(String name, int availability) {
+ this.name = name;
+ this.availability = availability;
+ }
+
+ public FixedValueFeature(String name, boolean available) {
+ this.name = name;
+ this.availability = available ? FEATURE_AVAILABILITY_MAX_VALUE : 0;
+ }
+
+ @Override
+ public String name() {
+ return null;
+ }
+
+ @Override
+ public int availability() {
+ return availability;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return availability() > 0;
+ }
+}
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/feature/SettableFeature.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/feature/SettableFeature.java
new file mode 100644
index 0000000..f175bf0
--- /dev/null
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/feature/SettableFeature.java
@@ -0,0 +1,41 @@
+package org.apache.bookkeeper.feature;
+
+/*
+ *
+ * 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.
+ *
+ */
+
+public class SettableFeature extends FixedValueFeature {
+ public SettableFeature(String name, int initialAvailability) {
+ super(name, initialAvailability);
+ }
+
+ public SettableFeature(String name, boolean isAvailabile) {
+ super(name, isAvailabile);
+ }
+
+ public void set(int availability) {
+ this.availability = availability;
+ }
+
+ public void set(boolean isAvailabile) {
+ this.availability = isAvailabile ? FEATURE_AVAILABILITY_MAX_VALUE : 0;
+ }
+
+}
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/feature/SettableFeatureProvider.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/feature/SettableFeatureProvider.java
new file mode 100644
index 0000000..e21ad9d
--- /dev/null
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/feature/SettableFeatureProvider.java
@@ -0,0 +1,48 @@
+package org.apache.bookkeeper.feature;
+
+/*
+ *
+ * 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.
+ *
+ */
+
+/**
+ * A provider will provide settable features.
+ */
+public class SettableFeatureProvider extends CacheableFeatureProvider<SettableFeature> {
+
+ public final static FeatureProvider DISABLE_ALL = new SettableFeatureProvider("", 0);
+
+ protected final int availability;
+
+ public SettableFeatureProvider(String scope, int availability) {
+ super(scope);
+ this.availability = availability;
+ }
+
+ @Override
+ protected SettableFeature makeFeature(String featureName) {
+ return new SettableFeature(featureName, availability);
+ }
+
+ @Override
+ protected FeatureProvider makeProvider(String fullScopeName) {
+ return new SettableFeatureProvider(fullScopeName, availability);
+ }
+
+}