You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by fm...@apache.org on 2014/01/30 09:00:45 UTC
svn commit: r1562712 - in
/sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags:
./ impl/
Author: fmeschbe
Date: Thu Jan 30 08:00:45 2014
New Revision: 1562712
URL: http://svn.apache.org/r1562712
Log:
SLING-3350 Simplify API and implementation:
- Remove ClientContext interface (clients directly use Features service)
- Add feature flag caching in the ExecutionContext
- Improve API doc
- Merge service implementations into FeatureManager
- Remove ResourceDecorator (see issue for reasons)
- Only one filter registration (extract ResourceResolver from request attr)
Removed:
sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/ClientContext.java
sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java
sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/impl/CurrentClientContextFilter.java
sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/impl/FeatureResourceDecorator.java
sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/impl/FeatureWebConsolePlugin.java
sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/impl/FeaturesImpl.java
Modified:
sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/ExecutionContext.java
sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/Feature.java
sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/Features.java
sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java
sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/package-info.java
Modified: sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/ExecutionContext.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/ExecutionContext.java?rev=1562712&r1=1562711&r2=1562712&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/ExecutionContext.java (original)
+++ sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/ExecutionContext.java Thu Jan 30 08:00:45 2014
@@ -30,14 +30,14 @@ import aQute.bnd.annotation.ProviderType
* provided to the {@link Feature#isEnabled(ExecutionContext)} to help
* evaluating whether the feature is enabled or not.
* <p>
- * The {@link Features} service {@link ClientContext} generating methods create
- * an instance of this to collect the enabled {@link Feature} services for the
- * creation of the {@link ClientContext} instance.
- * <p>
* This object provides access to live data and must only be used to read
* information. Modifying content through a {@code ResourceResolver} directly or
* indirectly provided by this object is considered inappropriate and faulty
* behavior.
+ * <p>
+ * Instances of this interface are provided by the feature manager to the
+ * {@link Feature} services. This interface is not intended to be implemented by
+ * client and application code.
*/
@ProviderType
public interface ExecutionContext {
@@ -47,11 +47,8 @@ public interface ExecutionContext {
* may influence the decision whether a {@link Feature} is enabled or not.
* If a {@code HttpServletRequest} object is not available in the context,
* this method may return {@code null}.
- * <p>
- * In a Sling request processing context, the {@code HttpServletRequest}
- * object returned may actually be a {@code SlingHttpServletRequest}.
*
- * @return the request or <code>null</code>
+ * @return the request or {@code null}
*/
HttpServletRequest getRequest();
@@ -61,7 +58,7 @@ public interface ExecutionContext {
* If a {@code ResourceResolver} object is not available in the context,
* this method may return {@code null}.
*
- * @return the resource resolver
+ * @return the resource resolver or {@code null}
*/
ResourceResolver getResourceResolver();
}
Modified: sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/Feature.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/Feature.java?rev=1562712&r1=1562711&r2=1562712&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/Feature.java (original)
+++ sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/Feature.java Thu Jan 30 08:00:45 2014
@@ -22,31 +22,18 @@ import aQute.bnd.annotation.ConsumerType
/**
* A feature is defined by its name. Features are registered as OSGi services.
- * This interface is expected to be implemented by feature providers.
* <p>
* Feature {@link #getName() names} should be globally unique. If multiple
* features have the same name, the feature with the highest service ranking is
- * accessible through the {@link Features} service and the {@link ClientContext}.
+ * accessible through the {@link Features} service while those with lower
+ * service rankings are ignored.
+ * <p>
+ * This interface is expected to be implemented by feature providers.
*/
@ConsumerType
public interface Feature {
/**
- * Checks whether the feature is enabled for the given execution context.
- * <p>
- * Multiple calls to this method may but are not required to return the same
- * value. For example the return value may depend on the time of day, some
- * random number or some information provided by the given
- * {@link ExecutionContext}.
- *
- * @param context The {@link ExecutionContext} providing a context to
- * evaluate whether the feature is enabled or not.
- * @return {@code true} if this {@code Feature} is enabled in the given
- * {@link ExecutionContext}.
- */
- boolean isEnabled(ExecutionContext context);
-
- /**
* The name of the feature.
*
* @return The name of this feature which must not be {@code null} or an
@@ -61,4 +48,24 @@ public interface Feature {
* {@code null} or an empty string.
*/
String getDescription();
+
+ /**
+ * Checks whether the feature is enabled for the given execution context.
+ * <p>
+ * Multiple calls to this method may but are not required to return the same
+ * value. For example the return value may depend on the time of day, some
+ * random number or some information provided by the given
+ * {@link ExecutionContext}.
+ * <p>
+ * This method is called by the {@link Feature} manager and is not intended
+ * to be called by application code directly.
+ *
+ * @param context The {@link ExecutionContext} providing a context to
+ * evaluate whether the feature is enabled or not.
+ * Implementations must not hold on to this context instance or
+ * the values provided for longer than executing this method.
+ * @return {@code true} if this {@code Feature} is enabled in the given
+ * {@link ExecutionContext}.
+ */
+ boolean isEnabled(ExecutionContext context);
}
Modified: sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/Features.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/Features.java?rev=1562712&r1=1562711&r2=1562712&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/Features.java (original)
+++ sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/Features.java Thu Jan 30 08:00:45 2014
@@ -18,45 +18,34 @@
*/
package org.apache.sling.featureflags;
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.sling.api.resource.ResourceResolver;
-
import aQute.bnd.annotation.ProviderType;
/**
- * The features service is the central gateway for feature handling. It can be
- * used to query the available features and to create client contexts to be used
- * for enabled feature checking.
+ * The {@code Features} service is the applications access point to the Feature
+ * Flag functionality. It can be used to query the available features and to
+ * create client contexts to be used for enabled feature checking.
*/
@ProviderType
public interface Features {
/**
- * Get the list of all available (known) feature names.
+ * Get the list of all (known) features.
* <p>
* Features are known if they are registered as {@link Feature} services or
* are configured with OSGi configuration whose factory PID is
* {@code org.apache.sling.featureflags.Feature}.
*
- * @return The names of the known features
+ * @return The known features
*/
- String[] getAvailableFeatureNames();
+ Feature[] getFeatures();
/**
- * Get the list of all available (known) features.
+ * Returns the feature with the given name.
* <p>
* Features are known if they are registered as {@link Feature} services or
* are configured with OSGi configuration whose factory PID is
* {@code org.apache.sling.featureflags.Feature}.
*
- * @return The known features
- */
- Feature[] getAvailableFeatures();
-
- /**
- * Returns the feature with the given name.
- *
* @param name The name of the feature.
* @return The feature or <code>null</code> if not known or the name is an
* empty string or {@code null}.
@@ -64,62 +53,17 @@ public interface Features {
Feature getFeature(String name);
/**
- * Checks whether a feature with the given name is available (known).
+ * Returns {@code true} if a feature with the given name is known and
+ * enabled under the current {@link ExecutionContext}.
* <p>
* Features are known if they are registered as {@link Feature} services or
* are configured with OSGi configuration whose factory PID is
* {@code org.apache.sling.featureflags.Feature}.
*
- * @param featureName The name of the feature to check for availability.
- * @return {@code true} if the named feature is available.
- */
- boolean isAvailable(String featureName);
-
- /**
- * Returns the current client context. This method always returns a client
- * context object.
- *
- * @return A client context.
- */
- ClientContext getCurrentClientContext();
-
- /**
- * Create a client context for the resource resolver.
- * <p>
- * The {@link ClientContext} is a snapshot of the enablement state of the
- * features at the time of creation. A change in the feature enablement
- * state is not reflected in {@link ClientContext} objects created prior to
- * changing the state.
- * <p>
- * The {@link ClientContext} returned is not available through the
- * {@link #getCurrentClientContext()} method.
- *
- * @param resolver The {@code ResourceResolver} to base the
- * {@link ClientContext} on.
- * @return A newly created client context based on the given
- * {@code ResourceResolver}.
- * @throws IllegalArgumentException If {@code resolver} is {@code null}
- */
- ClientContext createClientContext(ResourceResolver resolver);
-
- /**
- * Create a client context for the request.
- * <p>
- * The {@link ClientContext} is a snapshot of the enablement state of the
- * features at the time of creation. A change in the feature enablement
- * state is not reflected in {@link ClientContext} objects created prior to
- * changing the state.
- * <p>
- * The {@link ClientContext} returned is not available through the
- * {@link #getCurrentClientContext()} method.
- *
- * @param request The {@code HttpServletRequest} to base the
- * {@link ClientContext} on. If this is a
- * {@code SlingHttpServletContext} the {@link ClientContext}'s
- * resource resolver is set to the request's resource resolver.
- * @return A newly created client context based on the given
- * {@code HttpServletRequest}.
- * @throws IllegalArgumentException If {@code request} is {@code null}
+ * @param name The name of the feature to check for enablement.
+ * @return {@code true} if the named feature is known and enabled.
+ * Specifically {@code false} is also returned if the named feature
+ * is not known.
*/
- ClientContext createClientContext(HttpServletRequest request);
+ boolean isEnabled(String name);
}
Modified: sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java?rev=1562712&r1=1562711&r2=1562712&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java (original)
+++ sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java Thu Jan 30 08:00:45 2014
@@ -18,41 +18,40 @@
*/
package org.apache.sling.featureflags.impl;
+import java.util.HashMap;
+import java.util.Map;
+
import javax.servlet.http.HttpServletRequest;
-import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.auth.core.AuthenticationSupport;
import org.apache.sling.featureflags.ExecutionContext;
+import org.apache.sling.featureflags.Feature;
/**
* Implementation of the provider context.
*/
public class ExecutionContextImpl implements ExecutionContext {
+ private static final String REQUEST_ATTRIBUTE_RESOLVER = "org.apache.sling.auth.core.ResourceResolver";
+
private final ResourceResolver resourceResolver;
private final HttpServletRequest request;
- public ExecutionContextImpl(final ResourceResolver resourceResolver) {
- this.request = null;
- this.resourceResolver = resourceResolver;
- }
+ private final Map<String, Boolean> featureCache;
public ExecutionContextImpl(final HttpServletRequest request) {
- this.request = request;
- ResourceResolver resolver = (request instanceof SlingHttpServletRequest)
- ? ((SlingHttpServletRequest) request).getResourceResolver()
- : null;
- if ( resolver == null ) {
- // get ResourceResolver (set by AuthenticationSupport)
- final Object resolverObject = request.getAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_RESOLVER);
- resolver = (resolverObject instanceof ResourceResolver)
- ? (ResourceResolver) resolverObject
- : null;
-
+ ResourceResolver resourceResolver = null;
+ if (request != null) {
+ Object resolverObject = request.getAttribute(REQUEST_ATTRIBUTE_RESOLVER);
+ if (resolverObject instanceof ResourceResolver) {
+ resourceResolver = (ResourceResolver) resolverObject;
+ }
}
- this.resourceResolver = resolver;
+
+ this.request = request;
+ this.resourceResolver = resourceResolver;
+ this.featureCache = new HashMap<String, Boolean>();
}
@Override
@@ -64,4 +63,14 @@ public class ExecutionContextImpl implem
public ResourceResolver getResourceResolver() {
return this.resourceResolver;
}
+
+ boolean isEnabled(Feature feature) {
+ final String name = feature.getName();
+ Boolean entry = this.featureCache.get(name);
+ if (entry == null) {
+ entry = Boolean.valueOf(feature.isEnabled(this));
+ this.featureCache.put(name, entry);
+ }
+ return entry;
+ }
}
Modified: sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java?rev=1562712&r1=1562711&r2=1562712&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java (original)
+++ sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java Thu Jan 30 08:00:45 2014
@@ -18,34 +18,36 @@
*/
package org.apache.sling.featureflags.impl;
+import java.io.IOException;
+import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
-import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
-import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.ConfigurationPolicy;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
-import org.apache.sling.api.resource.ResourceDecorator;
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.featureflags.ClientContext;
-import org.apache.sling.featureflags.ExecutionContext;
+import org.apache.felix.scr.annotations.Service;
import org.apache.sling.featureflags.Feature;
import org.apache.sling.featureflags.Features;
-import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
-import org.osgi.framework.ServiceRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -53,71 +55,114 @@ import org.slf4j.LoggerFactory;
* This service implements the feature handling. It keeps track of all
* {@link Feature} services.
*/
-@Component
+@Component(policy = ConfigurationPolicy.IGNORE)
+@Service
@Reference(
name = "feature",
cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE,
policy = ReferencePolicy.DYNAMIC,
referenceInterface = Feature.class)
-public class FeatureManager {
+@Properties({
+ @Property(name = "felix.webconsole.label", value = "features"),
+ @Property(name = "felix.webconsole.title", value = "Features"),
+ @Property(name = "felix.webconsole.category", value = "Sling"),
+ @Property(name = "pattern", value = "/.*"),
+ @Property(name = "service.ranking", intValue = 0x4000)
+})
+public class FeatureManager implements Features, Filter, Servlet {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
- private final ThreadLocal<ClientContext> perThreadClientContext = new ThreadLocal<ClientContext>();
+ private final ThreadLocal<ExecutionContextImpl> perThreadClientContext = new ThreadLocal<ExecutionContextImpl>();
- private final ClientContext defaultClientContext = new ClientContext() {
- @Override
- public boolean isEnabled(final String featureName) {
- return false;
+ private final Map<String, List<FeatureDescription>> allFeatures = new HashMap<String, List<FeatureDescription>>();
+
+ private Map<String, Feature> activeFeatures = Collections.emptyMap();
+
+ private ServletConfig servletConfig;
+
+ //--- Features
+
+ public Feature[] getFeatures() {
+ final Map<String, Feature> activeFeatures = this.activeFeatures;
+ return activeFeatures.values().toArray(new Feature[activeFeatures.size()]);
+ }
+
+ public Feature getFeature(final String name) {
+ return this.activeFeatures.get(name);
+ }
+
+ public boolean isEnabled(String featureName) {
+ final Feature feature = this.getFeature(featureName);
+ if (feature != null) {
+ return getCurrentExecutionContext().isEnabled(feature);
}
+ return false;
+ }
- @Override
- public Collection<Feature> getEnabledFeatures() {
- return Collections.emptyList();
+ //--- Filter
+
+ @Override
+ public void init(FilterConfig filterConfig) {
+ // nothing todo do
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
+ ServletException {
+ try {
+ this.pushContext((HttpServletRequest) request);
+ chain.doFilter(request, response);
+ } finally {
+ this.popContext();
}
- };
+ }
- private final Map<String, List<FeatureDescription>> allFeatures = new HashMap<String, List<FeatureDescription>>();
+ @Override
+ public void destroy() {
+ // method shared by Servlet and Filter interface
+ this.servletConfig = null;
+ }
- private Map<String, Feature> activeFeatures = Collections.emptyMap();
+ //--- Servlet
- private List<ServiceRegistration> services;
+ @Override
+ public void init(ServletConfig config) {
+ this.servletConfig = config;
+ }
- @SuppressWarnings("serial")
- @Activate
- private void activate(BundleContext bundleContext) {
- ArrayList<ServiceRegistration> services = new ArrayList<ServiceRegistration>();
- services.add(bundleContext.registerService(Features.class.getName(), new FeaturesImpl(this), null));
- services.add(bundleContext.registerService(ResourceDecorator.class.getName(),
- new FeatureResourceDecorator(this), null));
- services.add(bundleContext.registerService(Servlet.class.getName(), new FeatureWebConsolePlugin(this),
- new Hashtable<String, Object>() {
- {
- put("felix.webconsole.label", "features");
- put("felix.webconsole.title", "Features");
- put("felix.webconsole.category", "Sling");
- }
- }));
- services.add(bundleContext.registerService(Filter.class.getName(), new CurrentClientContextFilter(this),
- new Hashtable<String, Object>() {
- {
- put("pattern", "/.*");
- put("service.ranking", Integer.MIN_VALUE);
- }
- }));
- this.services = services;
+ @Override
+ public ServletConfig getServletConfig() {
+ return this.servletConfig;
}
- @Deactivate
- private void deactivate() {
- if (this.services != null) {
- for (ServiceRegistration service : this.services) {
- if (service != null) {
- service.unregister();
+ @Override
+ public String getServletInfo() {
+ return "Features";
+ }
+
+ @Override
+ public void service(ServletRequest req, ServletResponse res) throws IOException {
+ if ("GET".equals(((HttpServletRequest) req).getMethod())) {
+ final PrintWriter pw = res.getWriter();
+ final Feature[] features = getFeatures();
+ if (features == null || features.length == 0) {
+ pw.println("<p class='statline ui-state-highlight'>No Features currently defined</p>");
+ } else {
+ pw.printf("<p class='statline ui-state-highlight'>%d Feature(s) currently defined</p>%n",
+ features.length);
+ pw.println("<table class='nicetable'>");
+ pw.println("<tr><th>Name</th><th>Description</th><th>Enabled</th></tr>");
+ final ExecutionContextImpl ctx = getCurrentExecutionContext();
+ for (final Feature feature : features) {
+ pw.printf("<tr><td>%s</td><td>%s</td><td>%s</td></tr>%n", feature.getName(),
+ feature.getDescription(), ctx.isEnabled(feature));
}
+ pw.println("</table>");
}
- this.services.clear();
- this.services = null;
+ } else {
+ ((HttpServletResponse) res).sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
+ res.flushBuffer();
}
}
@@ -176,79 +221,17 @@ public class FeatureManager {
//--- Client Context management and access
- ClientContext getCurrentClientContext() {
- ClientContext result = perThreadClientContext.get();
- if (result == null) {
- result = defaultClientContext;
- }
- return result;
- }
-
- ClientContext setCurrentClientContext(final ServletRequest request) {
- final ClientContext current = perThreadClientContext.get();
- if (request instanceof HttpServletRequest) {
- final ExecutionContext providerContext = new ExecutionContextImpl((HttpServletRequest) request);
- final ClientContextImpl ctx = this.createClientContext(providerContext);
- perThreadClientContext.set(ctx);
- }
- return current;
- }
-
- void unsetCurrentClientContext(final ClientContext previous) {
- if (previous != null) {
- perThreadClientContext.set(previous);
- } else {
- perThreadClientContext.remove();
- }
- }
-
- ClientContext createClientContext(final ResourceResolver resolver) {
- if (resolver == null) {
- throw new IllegalArgumentException("Resolver must not be null.");
- }
- final ExecutionContext providerContext = new ExecutionContextImpl(resolver);
- final ClientContext ctx = this.createClientContext(providerContext);
- return ctx;
- }
-
- ClientContext createClientContext(final HttpServletRequest request) {
- if (request == null) {
- throw new IllegalArgumentException("Request must not be null.");
- }
- final ExecutionContext providerContext = new ExecutionContextImpl(request);
- final ClientContext ctx = this.createClientContext(providerContext);
- return ctx;
+ void pushContext(final HttpServletRequest request) {
+ this.perThreadClientContext.set(new ExecutionContextImpl(request));
}
- private ClientContextImpl createClientContext(final ExecutionContext providerContext) {
- final Map<String, Feature> enabledFeatures = new HashMap<String, Feature>();
- for (final Map.Entry<String, Feature> entry : this.activeFeatures.entrySet()) {
- if (entry.getValue().isEnabled(providerContext)) {
- enabledFeatures.put(entry.getKey(), entry.getValue());
- }
- }
-
- return new ClientContextImpl(providerContext, enabledFeatures);
- }
-
- //--- Feature access
-
- Feature[] getAvailableFeatures() {
- final Map<String, Feature> activeFeatures = this.activeFeatures;
- return activeFeatures.values().toArray(new Feature[activeFeatures.size()]);
- }
-
- Feature getFeature(final String name) {
- return this.activeFeatures.get(name);
- }
-
- String[] getAvailableFeatureNames() {
- final Map<String, Feature> activeFeatures = this.activeFeatures;
- return activeFeatures.keySet().toArray(new String[activeFeatures.size()]);
+ void popContext() {
+ this.perThreadClientContext.set(null);
}
- boolean isAvailable(final String featureName) {
- return this.activeFeatures.containsKey(featureName);
+ ExecutionContextImpl getCurrentExecutionContext() {
+ ExecutionContextImpl ctx = this.perThreadClientContext.get();
+ return (ctx != null) ? ctx : new ExecutionContextImpl(null);
}
/**
Modified: sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/package-info.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/package-info.java?rev=1562712&r1=1562711&r2=1562712&view=diff
==============================================================================
--- sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/package-info.java (original)
+++ sling/trunk/contrib/extensions/feature-flags/src/main/java/org/apache/sling/featureflags/package-info.java Thu Jan 30 08:00:45 2014
@@ -40,16 +40,18 @@
* <table>
* <tr>
* <td>{@code name}</td>
- * <td>Short name of this feature. This name is used to refer to this feature
+ * <td>Short name of the feature. This name is used to refer to the feature
* when checking for it to be enabled or not. This property is required
* and defaults to a name derived from the feature's class name and object
- * identity. It is strongly recommended to define a useful and unique for the feature</td>
+ * identity. It is strongly recommended to define a useful and unique name
+ * for the feature</td>
* </tr>
* <tr>
* <td>{@code description}</td>
* <td>Description for the feature. The intent is to describe the behavior
* of the application if this feature would be enabled. It is recommended
- * to define this property. The default value is the value of the name property.</td>
+ * to define this property. The default value is the name of the feature
+ * as derived from the {@code name} property.</td>
* </tr>
* <tr>
* <td>{@code enabled}</td>