You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:34:19 UTC

[sling-org-apache-sling-featureflags] annotated tag org.apache.sling.featureflags-1.0.0 created (now 24a472d)

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a change to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git.


      at 24a472d  (tag)
 tagging f839000e8a933f6fad69c32aff209bacb9048599 (commit)
      by Carsten Ziegeler
      on Mon Mar 31 12:08:36 2014 +0000

- Log -----------------------------------------------------------------
org.apache.sling.featureflags-1.0.0
-----------------------------------------------------------------------

This annotated tag includes the following new commits:

     new b660cb4  New Feature Flags prototype
     new 68ee646  Implemet hiding of resource and decorating
     new 93f4097  Take II for the feature flags, separate into different contexts to avoid duplicate evaluation
     new fae60b1  Take II for the feature flags, separate into different contexts to avoid duplicate evaluation
     new d262cb3  Update javadocs
     new 085cc03  Remove "extensions" from package name
     new 8bf3903  Take III, add Feature interface and support adapting to functionality interfaces
     new 3e0d594  Moving feature flags into trunk
     new 35ebee9  Take III, add Feature interface and support adapting to functionality interfaces
     new 7a1c95e  Remove FeatureProvider interface, Features are OSGi services now - rename ProviderContext to ExecutionContext
     new 9f8c00a  Remove FeatureProvider interface, Features are OSGi services now - rename ProviderContext to ExecutionContext
     new 62d89be  SLING-2698 - resource access security service for resource providers. Distinguish between context application and provider
     new 0416605  Use released Sling API
     new 5e66975  SLING-3148 Merge back from whiteboard/fmeschbe/featureflags/feature-flags
     new b5e22fe  SLING-3148 Set appropriate label for the configuration metatype
     new d7c9903  Fix some typos
     new a43e709  SLING-3346 Feature flag not respected
     new e2fe9d0  SLING-3148 : Get resource resolver from authentication support via request attribute
     new 7d315ba  SLING-3350 Simplify API and implementation:
     new 646abb7  SLING-3353 Move feature flags from contrib to bundles
     new 6bc6971  FELIX-3444 : Provide a switch to enable feature flags for the resource resolver
     new ff85fb8  SLING-3484 - Remove FeatureAuthenticationInfoPostProcessor and FeatureConstants, unneeded
     new 22dc66a  Add svn info, remove unused dep
     new 8ef0dda  [maven-release-plugin] prepare release org.apache.sling.featureflags-1.0.0
     new f839000  [maven-release-plugin]  copy for tag org.apache.sling.featureflags-1.0.0

The 25 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


-- 
To stop receiving notification emails like this one, please contact
['"commits@sling.apache.org" <co...@sling.apache.org>'].

[sling-org-apache-sling-featureflags] 18/25: SLING-3148 : Get resource resolver from authentication support via request attribute

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit e2fe9d0a6c7574aa0e08d7c1d06ea4b2288caa47
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Wed Jan 29 16:38:09 2014 +0000

    SLING-3148 : Get resource resolver from authentication support via request attribute
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/feature-flags@1562505 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                                      |  6 ++++++
 .../apache/sling/featureflags/impl/ExecutionContextImpl.java | 12 +++++++++++-
 .../org/apache/sling/featureflags/impl/FeatureManager.java   |  7 -------
 3 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/pom.xml b/pom.xml
index 75a28cd..6ea7c84 100644
--- a/pom.xml
+++ b/pom.xml
@@ -53,6 +53,12 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.auth.core</artifactId>
+            <version>1.1.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>servlet-api</artifactId>
         </dependency>
diff --git a/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java b/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java
index cfd673a..82f82da 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java
@@ -22,6 +22,7 @@ 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;
 
 /**
@@ -40,9 +41,18 @@ public class ExecutionContextImpl implements ExecutionContext {
 
     public ExecutionContextImpl(final HttpServletRequest request) {
         this.request = request;
-        this.resourceResolver = (request instanceof SlingHttpServletRequest)
+        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;
+
+        }
+        this.resourceResolver = resolver;
     }
 
     @Override
diff --git a/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java b/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
index fd87123..b5297a8 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
@@ -105,13 +105,6 @@ public class FeatureManager {
                     put("service.ranking", Integer.MIN_VALUE);
                 }
             }));
-        services.add(bundleContext.registerService(Filter.class.getName(), new CurrentClientContextFilter(this),
-            new Hashtable<String, Object>() {
-            {
-                put("sling.filter.scope", "REQUEST");
-                put("service.ranking", Integer.MIN_VALUE);
-            }
-        }));
         this.services = services;
     }
 

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 12/25: SLING-2698 - resource access security service for resource providers. Distinguish between context application and provider

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit 62d89be69430185a6db537bf1d501d09146a1aab
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Thu Jan 16 10:05:34 2014 +0000

    SLING-2698 - resource access security service for resource providers. Distinguish between context application and provider
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/feature-flags@1558734 13f79535-47bb-0310-9956-ffa450edef68
---
 .../java/org/apache/sling/featureflags/impl/ResourceAccessImpl.java     | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/main/java/org/apache/sling/featureflags/impl/ResourceAccessImpl.java b/src/main/java/org/apache/sling/featureflags/impl/ResourceAccessImpl.java
index 2dd05f1..8772cf3 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/ResourceAccessImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/ResourceAccessImpl.java
@@ -19,6 +19,7 @@
 package org.apache.sling.featureflags.impl;
 
 import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.resource.Resource;
@@ -32,6 +33,7 @@ import org.apache.sling.resourceaccesssecurity.ResourceAccessGate;
  */
 @Component
 @Service(value=ResourceAccessGate.class)
+@Property(name=ResourceAccessGate.CONTEXT, value=ResourceAccessGate.APPLICATION_CONTEXT)
 public class ResourceAccessImpl
     extends AllowingResourceAccessGate
     implements ResourceAccessGate {

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 14/25: SLING-3148 Merge back from whiteboard/fmeschbe/featureflags/feature-flags

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit 5e66975857d4ad36946668ae7da2cb9e125acdbb
Author: Felix Meschberger <fm...@apache.org>
AuthorDate: Tue Jan 28 08:32:39 2014 +0000

    SLING-3148 Merge back from whiteboard/fmeschbe/featureflags/feature-flags
    
    - Removed ResourceHiding and ResourceTypeHiding
    - Added ResourceDecorator support
    - Added WebConsole plugin
    - Added Feature factory configuration support
    - Added JavaDoc
    - Support non-Sling ExecutionContext
    - Porperly register ClientContext filter as Sling filter
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/feature-flags@1561994 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                            |  10 +-
 .../apache/sling/featureflags/ClientContext.java   |  22 +-
 .../sling/featureflags/ExecutionContext.java       |  35 ++-
 .../org/apache/sling/featureflags/Feature.java     |  38 ++--
 .../org/apache/sling/featureflags/Features.java    |  81 +++++--
 .../apache/sling/featureflags/ResourceHiding.java  |  41 ----
 .../sling/featureflags/ResourceTypeMapping.java    |  41 ----
 .../sling/featureflags/impl/ClientContextImpl.java |  49 ++---
 .../sling/featureflags/impl/ConfiguredFeature.java | 105 +++++++++
 .../impl/CurrentClientContextFilter.java           |  43 ++--
 .../featureflags/impl/ExecutionContextImpl.java    |  12 +-
 .../sling/featureflags/impl/FeatureManager.java    | 242 ++++++++++++---------
 ...atorImpl.java => FeatureResourceDecorator.java} |  40 ++--
 .../featureflags/impl/FeatureWebConsolePlugin.java |  74 +++++++
 .../sling/featureflags/impl/FeaturesImpl.java      |  17 +-
 .../featureflags/impl/ResourceAccessImpl.java      |  58 -----
 .../apache/sling/featureflags/package-info.java    |  42 +++-
 17 files changed, 563 insertions(+), 387 deletions(-)

diff --git a/pom.xml b/pom.xml
index 7f62fee..75a28cd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -43,19 +43,13 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.api</artifactId>
-            <version>2.5.0</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.resourceaccesssecurity</artifactId>
-            <version>0.0.1-SNAPSHOT</version>
+            <version>2.1.0</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.commons.osgi</artifactId>
-            <version>2.2.0</version>
+            <version>2.1.0</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/src/main/java/org/apache/sling/featureflags/ClientContext.java b/src/main/java/org/apache/sling/featureflags/ClientContext.java
index 61d5814..137e6ff 100644
--- a/src/main/java/org/apache/sling/featureflags/ClientContext.java
+++ b/src/main/java/org/apache/sling/featureflags/ClientContext.java
@@ -23,21 +23,31 @@ import java.util.Collection;
 import aQute.bnd.annotation.ProviderType;
 
 /**
- * The client context can be used by client code to check whether
- * a specific feature is enable.
- * A client context can be created through the {@link Features} service.
+ * The client context can be used by client code to check whether a specific
+ * feature is enable.
+ * <p>
+ * Prepared {@code ClientContext} instances are available through the
+ * {@link Features} service. Consumers of this interface are not expected to
+ * implent it.
  */
 @ProviderType
 public interface ClientContext {
 
     /**
-     * Returns <code>true</code> if the feature is enabled.
+     * Returns {@code true} if the named feature is enabled.
+     *
+     * @param featureName The name of the feature.
+     * @return {@code true} if the named feature is enabled. {@code false} is
+     *         returned if the named feature is not enabled, is not known or the
+     *         {@code featureName} parameter is {@code null} or an empty String.
      */
     boolean isEnabled(String featureName);
 
     /**
-     * Returns a list of all enabled features
-     * @return The list of features, the list might be empty.
+     * Returns a possibly empty collection of enabled {@link Feature} instances.
+     *
+     * @return The collection of enabled {@link Feature} instances. This
+     *         collection may be empty and is not modifiable.
      */
     Collection<Feature> getEnabledFeatures();
 }
diff --git a/src/main/java/org/apache/sling/featureflags/ExecutionContext.java b/src/main/java/org/apache/sling/featureflags/ExecutionContext.java
index d01bd67..14d684d 100644
--- a/src/main/java/org/apache/sling/featureflags/ExecutionContext.java
+++ b/src/main/java/org/apache/sling/featureflags/ExecutionContext.java
@@ -18,26 +18,49 @@
  */
 package org.apache.sling.featureflags;
 
-import org.apache.sling.api.SlingHttpServletRequest;
+import javax.servlet.http.HttpServletRequest;
+
 import org.apache.sling.api.resource.ResourceResolver;
 
 import aQute.bnd.annotation.ProviderType;
 
 /**
- * The provider context contains all information that is passed to a
- * {@link Feature} in order to check whether a feature is enabled.
+ * The {@code ExecutionContext} interface provides access to the context for
+ * evaluating whether a feature is enabled or not. Instances of this object are
+ * 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
+ * behaviour.
  */
 @ProviderType
 public interface ExecutionContext {
 
     /**
-     * Return the associated request if available
+     * Returns a {@code HttpServletRequest} object to retrieve information which
+     * 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>
      */
-    SlingHttpServletRequest getRequest();
+    HttpServletRequest getRequest();
 
     /**
-     * Return the associated resource resolver.
+     * Returns a {@code ResourceResolver} object to retrieve information which
+     * may influence the decision whether a {@link Feature} is enabled or not.
+     * If a {@code ResourceResolver} object is not available in the context,
+     * this method may return {@code null}.
+     *
      * @return the resource resolver
      */
     ResourceResolver getResourceResolver();
diff --git a/src/main/java/org/apache/sling/featureflags/Feature.java b/src/main/java/org/apache/sling/featureflags/Feature.java
index 5bec8fd..3984df5 100644
--- a/src/main/java/org/apache/sling/featureflags/Feature.java
+++ b/src/main/java/org/apache/sling/featureflags/Feature.java
@@ -18,37 +18,47 @@
  */
 package org.apache.sling.featureflags;
 
-import org.apache.sling.api.adapter.Adaptable;
-
 import aQute.bnd.annotation.ConsumerType;
 
 /**
- * A feature is defined by its name.
- * Depending on the functionality the feature implements it can
- * be adapted to different services, like
- * <ul>
- *   <li>{@link ResourceHiding}</li>
- *   <li>{@link ResourceTypeMapping}</li>
- * </ul>
- *
- * Features are registered as OSGi services.
+ * 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}.
  */
 @ConsumerType
-public interface Feature extends Adaptable {
+public interface Feature {
 
     /**
-     * Checks whether the feature is enabled for the current execution
-     * context.
+     * 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
+     *         empty string.
      */
     String getName();
 
     /**
      * The description of the feature.
+     *
+     * @return The optional description of this feature, which may be
+     *         {@code null} or an empty string.
      */
     String getDescription();
 }
diff --git a/src/main/java/org/apache/sling/featureflags/Features.java b/src/main/java/org/apache/sling/featureflags/Features.java
index 8b6a810..eb5faac 100644
--- a/src/main/java/org/apache/sling/featureflags/Features.java
+++ b/src/main/java/org/apache/sling/featureflags/Features.java
@@ -18,59 +18,108 @@
  */
 package org.apache.sling.featureflags;
 
-import org.apache.sling.api.SlingHttpServletRequest;
+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 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.
  */
 @ProviderType
 public interface Features {
 
     /**
-     * Get the list of all available feature names. A feature is available
-     * if there is a registered {@link Feature} service.
+     * Get the list of all available (known) feature names.
+     * <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
      */
     String[] getAvailableFeatureNames();
 
     /**
-     * Get the list of all available features. A feature is available
-     * if there is a registered {@link Feature} service.
+     * Get the list of all available (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 known features
      */
     Feature[] getAvailableFeatures();
 
     /**
      * Returns the feature with the given name.
-     * @return The feature or <code>null</code>
+     *
+     * @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}.
      */
     Feature getFeature(String name);
 
     /**
-     * Checks whether a feature with the given name is available.
-     * A feature is available if there is a registered {@link Feature} service.
+     * Checks whether a feature with the given name is available (known).
+     * <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
+     * 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.
-     * @throws IllegalArgumentException If resolver is null
+     * <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.
-     * @throws IllegalArgumentException If request is null
+     * <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}
      */
-    ClientContext createClientContext(SlingHttpServletRequest request);
+    ClientContext createClientContext(HttpServletRequest request);
 }
diff --git a/src/main/java/org/apache/sling/featureflags/ResourceHiding.java b/src/main/java/org/apache/sling/featureflags/ResourceHiding.java
deleted file mode 100644
index d19fab6..0000000
--- a/src/main/java/org/apache/sling/featureflags/ResourceHiding.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.
- */
-package org.apache.sling.featureflags;
-
-import org.apache.sling.api.resource.Resource;
-
-import aQute.bnd.annotation.ConsumerType;
-
-/**
- * A {@link Feature} which is hiding resources can be adapted to
- * this service interface.
- */
-@ConsumerType
-public interface ResourceHiding {
-
-    /**
-     * Checks whether a resource should be hidden for a feature.
-     * This check is only executed if {@link Feature#isEnabled(ExecutionContext)}
-     * return true for the given feature/context. The caller of this
-     * method must ensure to call {@link Feature#isEnabled(ExecutionContext)}
-     * before calling this method and only call this method if
-     * {@link Feature#isEnabled(ExecutionContext)} returned <code>true</code>
-     */
-    boolean hideResource(Resource resource);
-}
diff --git a/src/main/java/org/apache/sling/featureflags/ResourceTypeMapping.java b/src/main/java/org/apache/sling/featureflags/ResourceTypeMapping.java
deleted file mode 100644
index a9ca5f4..0000000
--- a/src/main/java/org/apache/sling/featureflags/ResourceTypeMapping.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.
- */
-package org.apache.sling.featureflags;
-
-import java.util.Map;
-
-import aQute.bnd.annotation.ConsumerType;
-
-/**
- * A {@link Feature} which is mapping resource types can be adapted to
- * this service interface.
- */
-@ConsumerType
-public interface ResourceTypeMapping {
-
-    /**
-     * Returns the resource type mapping for a feature.
-     * This mapping is only executed if {@link Feature#isEnabled(ExecutionContext)}
-     * return true for the given feature/context. The caller of this
-     * method must ensure to call {@link Feature#isEnabled(ExecutionContext)}
-     * before calling this method and only call this method if
-     * {@link Feature#isEnabled(ExecutionContext)} returned <code>true</code>
-     */
-    Map<String, String> getResourceTypeMapping();
-}
diff --git a/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java b/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java
index b71ebe4..dc02b25 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java
@@ -21,15 +21,13 @@ package org.apache.sling.featureflags.impl;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.sling.api.resource.ResourceDecorator;
 import org.apache.sling.featureflags.ClientContext;
 import org.apache.sling.featureflags.Feature;
 import org.apache.sling.featureflags.ExecutionContext;
-import org.apache.sling.featureflags.ResourceHiding;
-import org.apache.sling.featureflags.ResourceTypeMapping;
 
 /**
  * Implementation of the client context
@@ -38,28 +36,22 @@ public class ClientContextImpl implements ClientContext {
 
     private final ExecutionContext featureContext;
 
-    private final List<Feature> enabledFeatures;
+    private final Map<String, Feature> enabledFeatures;
 
-    private final List<ResourceHiding> hidingFeatures;
+    private final List<ResourceDecorator> resourceDecorators;
 
-    private final Map<String, String> mapperFeatures = new HashMap<String, String>();
-
-    public ClientContextImpl(final ExecutionContext featureContext, final List<Feature> features) {
-        this.enabledFeatures = Collections.unmodifiableList(features);
-        final List<ResourceHiding> hiding = new ArrayList<ResourceHiding>();
-        for(final Feature f : this.enabledFeatures) {
-            final ResourceHiding rh = f.adaptTo(ResourceHiding.class);
-            if ( rh != null ) {
-                hiding.add(rh);
-            }
-            final ResourceTypeMapping rm = f.adaptTo(ResourceTypeMapping.class);
-            if ( rm != null ) {
-                final Map<String, String> mapping = rm.getResourceTypeMapping();
-                mapperFeatures.putAll(mapping);
+    public ClientContextImpl(final ExecutionContext featureContext, final Map<String, Feature> features) {
+        ArrayList<ResourceDecorator> resourceDecorators = new ArrayList<ResourceDecorator>(features.size());
+        for (final Feature f : features.values()) {
+            if (f instanceof ResourceDecorator) {
+                resourceDecorators.add((ResourceDecorator) f);
             }
         }
-        this.hidingFeatures = hiding;
+        resourceDecorators.trimToSize();
+
         this.featureContext = featureContext;
+        this.enabledFeatures = Collections.unmodifiableMap(features);
+        this.resourceDecorators = Collections.unmodifiableList(resourceDecorators);
     }
 
     public ExecutionContext getFeatureContext() {
@@ -68,24 +60,15 @@ public class ClientContextImpl implements ClientContext {
 
     @Override
     public boolean isEnabled(final String featureName) {
-        for(final Feature f : this.enabledFeatures) {
-            if ( featureName.equals(f.getName()) ) {
-                return true;
-            }
-        }
-        return false;
+        return this.enabledFeatures.get(featureName) != null;
     }
 
     @Override
     public Collection<Feature> getEnabledFeatures() {
-        return this.enabledFeatures;
-    }
-
-    public Collection<ResourceHiding> getHidingFeatures() {
-        return this.hidingFeatures;
+        return this.enabledFeatures.values();
     }
 
-    public Map<String, String> getResourceTypeMapping() {
-        return this.mapperFeatures;
+    public List<ResourceDecorator> getResourceDecorators() {
+        return this.resourceDecorators;
     }
 }
diff --git a/src/main/java/org/apache/sling/featureflags/impl/ConfiguredFeature.java b/src/main/java/org/apache/sling/featureflags/impl/ConfiguredFeature.java
new file mode 100644
index 0000000..1f4db86
--- /dev/null
+++ b/src/main/java/org/apache/sling/featureflags/impl/ConfiguredFeature.java
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+package org.apache.sling.featureflags.impl;
+
+import java.util.Map;
+
+import javax.servlet.ServletRequest;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.ConfigurationPolicy;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.featureflags.ExecutionContext;
+import org.apache.sling.featureflags.Feature;
+import org.osgi.framework.Constants;
+
+@Component(
+        name = "org.apache.sling.featureflags.Feature",
+        metatype = true,
+        configurationFactory = true,
+        policy = ConfigurationPolicy.REQUIRE,
+        label = "Statically Configured Feature",
+        description = "Allows for the definition of statically configured features which are defined and enabled through OSGi configuration")
+@Service
+public class ConfiguredFeature implements Feature {
+
+    private static final String PROP_FEATURE = "feature";
+
+    @Property(label = "Name", description = "Short name of this feature. This name is used "
+        + "to refer to this 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")
+    private static final String NAME = "name";
+
+    @Property(label = "Description", description = "Description for the feature. The "
+        + "intent is to descibe the behaviour 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.")
+    private static final String DESCRIPTION = "description";
+
+    @Property(boolValue = false, label = "Enabled", description = "Boolean flag indicating whether the feature is "
+        + "enabled or not by this configuration")
+    private static final String ENABLED = "enabled";
+
+    private String name;
+
+    private String description;
+
+    private boolean enabled;
+
+    @Activate
+    private void activate(final Map<String, Object> configuration) {
+        final String pid = PropertiesUtil.toString(configuration.get(Constants.SERVICE_PID), getClass().getName() + "$"
+            + System.identityHashCode(this));
+        this.name = PropertiesUtil.toString(configuration.get(NAME), pid);
+        this.description = PropertiesUtil.toString(configuration.get(DESCRIPTION), this.name);
+        this.enabled = PropertiesUtil.toBoolean(configuration.get(ENABLED), false);
+    }
+
+    @Override
+    public boolean isEnabled(ExecutionContext context) {
+
+        // Request Parameter Override
+        ServletRequest request = context.getRequest();
+        if (request != null) {
+            String[] features = request.getParameterValues(PROP_FEATURE);
+            if (features != null) {
+                for (String feature : features) {
+                    if (this.name.equals(feature)) {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        return this.enabled;
+    }
+
+    @Override
+    public String getName() {
+        return this.name;
+    }
+
+    @Override
+    public String getDescription() {
+        return this.description;
+    }
+}
diff --git a/src/main/java/org/apache/sling/featureflags/impl/CurrentClientContextFilter.java b/src/main/java/org/apache/sling/featureflags/impl/CurrentClientContextFilter.java
index 9399666..da6287f 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/CurrentClientContextFilter.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/CurrentClientContextFilter.java
@@ -26,45 +26,38 @@ import javax.servlet.FilterConfig;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
-
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.Service;
-import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.featureflags.ClientContext;
 
 /**
- * This general servlet filter sets the current client context to the
- * current request.
+ * This general servlet filter sets the current client context to the current
+ * request.
  */
-@Component
-@Service(value=Filter.class)
-@Property(name="pattern", value="/.*")
 public class CurrentClientContextFilter implements Filter {
 
-    @Reference
-    private FeatureManager manager;
+    private final FeatureManager featureManager;
+
+    public CurrentClientContextFilter(final FeatureManager featureManager) {
+        this.featureManager = featureManager;
+    }
 
     @Override
-    public void doFilter(final ServletRequest req, final ServletResponse res,
-            final FilterChain chain)
-    throws IOException, ServletException {
-        if ( req instanceof SlingHttpServletRequest ) {
-            manager.setCurrentClientContext((SlingHttpServletRequest)req);
-        }
+    public void init(final FilterConfig config) {
+        // nothing to do
+    }
+
+    @Override
+    public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain)
+            throws IOException, ServletException {
+
+        ClientContext current = this.featureManager.setCurrentClientContext(req);
         try {
             chain.doFilter(req, res);
         } finally {
-            manager.unsetCurrentClientContext();
+            this.featureManager.unsetCurrentClientContext(current);
         }
     }
 
     @Override
-    public void init(final FilterConfig config) throws ServletException {
-        // nothing to do
-    }
-
-    @Override
     public void destroy() {
         // nothing to do
     }
diff --git a/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java b/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java
index 555575f..cfd673a 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java
@@ -18,6 +18,8 @@
  */
 package org.apache.sling.featureflags.impl;
 
+import javax.servlet.http.HttpServletRequest;
+
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.featureflags.ExecutionContext;
@@ -29,20 +31,22 @@ public class ExecutionContextImpl implements ExecutionContext {
 
     private final ResourceResolver resourceResolver;
 
-    private final SlingHttpServletRequest request;
+    private final HttpServletRequest request;
 
     public ExecutionContextImpl(final ResourceResolver resourceResolver) {
         this.request = null;
         this.resourceResolver = resourceResolver;
     }
 
-    public ExecutionContextImpl(final SlingHttpServletRequest request) {
+    public ExecutionContextImpl(final HttpServletRequest request) {
         this.request = request;
-        this.resourceResolver = request.getResourceResolver();
+        this.resourceResolver = (request instanceof SlingHttpServletRequest)
+                ? ((SlingHttpServletRequest) request).getResourceResolver()
+                : null;
     }
 
     @Override
-    public SlingHttpServletRequest getRequest() {
+    public HttpServletRequest getRequest() {
         return this.request;
     }
 
diff --git a/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java b/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
index fd601f6..61b5641 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
@@ -22,51 +22,116 @@ 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 java.util.TreeMap;
 
+import javax.servlet.Filter;
+import javax.servlet.Servlet;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+
+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.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.ReferencePolicy;
-import org.apache.sling.api.SlingHttpServletRequest;
+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.sling.featureflags.Feature;
 import org.apache.sling.featureflags.Features;
-import org.apache.sling.featureflags.ExecutionContext;
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * This service implements the feature handling.
- * It keeps track of all {@link Feature} services.
+ * This service implements the feature handling. It keeps track of all
+ * {@link Feature} services.
  */
 @Component
-@Reference(name="feature",
-           cardinality=ReferenceCardinality.OPTIONAL_MULTIPLE,
-           policy=ReferencePolicy.DYNAMIC,
-           referenceInterface=Feature.class)
-public class FeatureManager implements Features {
+@Reference(
+        name = "feature",
+        cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE,
+        policy = ReferencePolicy.DYNAMIC,
+        referenceInterface = Feature.class)
+public class FeatureManager {
 
     private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
+    private final ThreadLocal<ClientContext> perThreadClientContext = new ThreadLocal<ClientContext>();
+
+    private final ClientContext defaultClientContext = new ClientContext() {
+        @Override
+        public boolean isEnabled(final String featureName) {
+            return false;
+        }
+
+        @Override
+        public Collection<Feature> getEnabledFeatures() {
+            return Collections.emptyList();
+        }
+    };
+
     private final Map<String, List<FeatureDescription>> allFeatures = new HashMap<String, List<FeatureDescription>>();
 
-    private Map<String, FeatureDescription> activeFeatures = new TreeMap<String, FeatureDescription>();
+    private Map<String, Feature> activeFeatures = Collections.emptyMap();
+
+    private List<ServiceRegistration> services;
+
+    @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("sling.filter.scope", "REQUEST");
+                    put("service.ranking", Integer.MIN_VALUE);
+                }
+            }));
+        this.services = services;
+    }
 
-    /**
-     * Bind a new feature
-     */
-    protected void bindFeature(final Feature f, final Map<String, Object> props) {
-        synchronized ( this.allFeatures ) {
+    @Deactivate
+    private void deactivate() {
+        if (this.services != null) {
+            for (ServiceRegistration service : this.services) {
+                if (service != null) {
+                    service.unregister();
+                }
+            }
+            this.services.clear();
+            this.services = null;
+        }
+    }
+
+    //--- Feature binding
+
+    // bind method for Feature services
+    @SuppressWarnings("unused")
+    private void bindFeature(final Feature f, final Map<String, Object> props) {
+        synchronized (this.allFeatures) {
             final String name = f.getName();
             final FeatureDescription info = new FeatureDescription(f, props);
 
             List<FeatureDescription> candidates = this.allFeatures.get(name);
-            if ( candidates == null ) {
+            if (candidates == null) {
                 candidates = new ArrayList<FeatureDescription>();
                 this.allFeatures.put(name, candidates);
             }
@@ -77,18 +142,17 @@ public class FeatureManager implements Features {
         }
     }
 
-    /**
-     * Unbind a feature
-     */
-    protected void unbindFeature(final Feature f, final Map<String, Object> props) {
-        synchronized ( this.allFeatures ) {
+    // unbind method for Feature services
+    @SuppressWarnings("unused")
+    private void unbindFeature(final Feature f, final Map<String, Object> props) {
+        synchronized (this.allFeatures) {
             final String name = f.getName();
             final FeatureDescription info = new FeatureDescription(f, props);
 
             final List<FeatureDescription> candidates = this.allFeatures.get(name);
-            if ( candidates != null ) { // sanity check
+            if (candidates != null) { // sanity check
                 candidates.remove(info);
-                if ( candidates.size() == 0 ) {
+                if (candidates.size() == 0) {
                     this.allFeatures.remove(name);
                 }
             }
@@ -96,56 +160,50 @@ public class FeatureManager implements Features {
         }
     }
 
+    // calculates map of active features (eliminating Feature name
+    // collisions). Must be called while synchronized on this.allFeatures
     private void calculateActiveProviders() {
-        final Map<String, FeatureDescription> activeMap = new TreeMap<String, FeatureDescription>();
-        for(final Map.Entry<String, List<FeatureDescription>> entry : this.allFeatures.entrySet()) {
+        final Map<String, Feature> activeMap = new HashMap<String, Feature>();
+        for (final Map.Entry<String, List<FeatureDescription>> entry : this.allFeatures.entrySet()) {
             final FeatureDescription desc = entry.getValue().get(0);
-
-            activeMap.put(entry.getKey(), desc);
-            if ( entry.getValue().size() > 1 ) {
+            activeMap.put(entry.getKey(), desc.feature);
+            if (entry.getValue().size() > 1) {
                 logger.warn("More than one feature service for feature {}", entry.getKey());
             }
         }
         this.activeFeatures = activeMap;
     }
 
-    private final ThreadLocal<ClientContextImpl> perThreadClientContext = new ThreadLocal<ClientContextImpl>();
-
-    private final ClientContext defaultClientContext = new ClientContext() {
-
-        @Override
-        public boolean isEnabled(final String featureName) {
-            return false;
-        }
-
-        @Override
-        public Collection<Feature> getEnabledFeatures() {
-            return Collections.emptyList();
-        }
-    };
+    //--- Client Context management and access
 
-    @Override
-    public ClientContext getCurrentClientContext() {
+    ClientContext getCurrentClientContext() {
         ClientContext result = perThreadClientContext.get();
-        if ( result == null ) {
+        if (result == null) {
             result = defaultClientContext;
         }
         return result;
     }
 
-    public void setCurrentClientContext(final SlingHttpServletRequest request) {
-        final ExecutionContext providerContext = new ExecutionContextImpl(request);
-        final ClientContextImpl ctx = this.createClientContext(providerContext);
-        perThreadClientContext.set(ctx);
+    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;
     }
 
-    public void unsetCurrentClientContext() {
-        perThreadClientContext.remove();
+    void unsetCurrentClientContext(final ClientContext previous) {
+        if (previous != null) {
+            perThreadClientContext.set(previous);
+        } else {
+            perThreadClientContext.remove();
+        }
     }
 
-    @Override
-    public ClientContext createClientContext(final ResourceResolver resolver) {
-        if ( resolver == null ) {
+    ClientContext createClientContext(final ResourceResolver resolver) {
+        if (resolver == null) {
             throw new IllegalArgumentException("Resolver must not be null.");
         }
         final ExecutionContext providerContext = new ExecutionContextImpl(resolver);
@@ -153,9 +211,8 @@ public class FeatureManager implements Features {
         return ctx;
     }
 
-    @Override
-    public ClientContext createClientContext(final SlingHttpServletRequest request) {
-        if ( request == null ) {
+    ClientContext createClientContext(final HttpServletRequest request) {
+        if (request == null) {
             throw new IllegalArgumentException("Request must not be null.");
         }
         final ExecutionContext providerContext = new ExecutionContextImpl(request);
@@ -164,75 +221,64 @@ public class FeatureManager implements Features {
     }
 
     private ClientContextImpl createClientContext(final ExecutionContext providerContext) {
-        final List<Feature> enabledFeatures = new ArrayList<Feature>();
-
-        for(final Map.Entry<String, FeatureDescription> entry : this.activeFeatures.entrySet()) {
-            final Feature f = entry.getValue().feature;
-
-            if ( entry.getValue().feature.isEnabled(providerContext) ) {
-                enabledFeatures.add(f);
+        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());
             }
         }
 
-        final ClientContextImpl ctx = new ClientContextImpl(providerContext, enabledFeatures);
-        return ctx;
+        return new ClientContextImpl(providerContext, enabledFeatures);
     }
 
-    @Override
-    public Feature[] getAvailableFeatures() {
-        final List<Feature> result = new ArrayList<Feature>();
-        for(final Map.Entry<String, FeatureDescription> entry : this.activeFeatures.entrySet()) {
-            final Feature f = entry.getValue().feature;
-            result.add(f);
-        }
-        return result.toArray(new Feature[result.size()]);
+    //--- Feature access
+
+    Feature[] getAvailableFeatures() {
+        final Map<String, Feature> activeFeatures = this.activeFeatures;
+        return activeFeatures.values().toArray(new Feature[activeFeatures.size()]);
     }
 
-    @Override
-    public Feature getFeature(final String name) {
-        final FeatureDescription desc = this.activeFeatures.get(name);
-        if ( desc != null ) {
-            return desc.feature;
-        }
-        return null;
+    Feature getFeature(final String name) {
+        return this.activeFeatures.get(name);
     }
 
-    @Override
-    public String[] getAvailableFeatureNames() {
-        return this.activeFeatures.keySet().toArray(new String[this.activeFeatures.size()]);
+    String[] getAvailableFeatureNames() {
+        final Map<String, Feature> activeFeatures = this.activeFeatures;
+        return activeFeatures.keySet().toArray(new String[activeFeatures.size()]);
     }
 
-    @Override
-    public boolean isAvailable(final String featureName) {
+    boolean isAvailable(final String featureName) {
         return this.activeFeatures.containsKey(featureName);
     }
 
     /**
-     * Internal class caching some feature meta data like service id and ranking.
+     * Internal class caching some feature meta data like service id and
+     * ranking.
      */
     private final static class FeatureDescription implements Comparable<FeatureDescription> {
 
         public final int ranking;
+
         public final long serviceId;
+
         public final Feature feature;
 
-        public FeatureDescription(final Feature feature,
-                final Map<String, Object> props) {
+        public FeatureDescription(final Feature feature, final Map<String, Object> props) {
             this.feature = feature;
             final Object sr = props.get(Constants.SERVICE_RANKING);
-            if ( sr == null || !(sr instanceof Integer)) {
-                this.ranking = 0;
+            if (sr instanceof Integer) {
+                this.ranking = (Integer) sr;
             } else {
-                this.ranking = (Integer)sr;
+                this.ranking = 0;
             }
-            this.serviceId = (Long)props.get(Constants.SERVICE_ID);
+            this.serviceId = (Long) props.get(Constants.SERVICE_ID);
         }
 
         @Override
         public int compareTo(final FeatureDescription o) {
-            if ( this.ranking < o.ranking ) {
+            if (this.ranking < o.ranking) {
                 return 1;
-            } else if (this.ranking > o.ranking ) {
+            } else if (this.ranking > o.ranking) {
                 return -1;
             }
             // If ranks are equal, then sort by service id in descending order.
@@ -241,8 +287,8 @@ public class FeatureManager implements Features {
 
         @Override
         public boolean equals(final Object obj) {
-            if ( obj instanceof FeatureDescription ) {
-                return ((FeatureDescription)obj).serviceId == this.serviceId;
+            if (obj instanceof FeatureDescription) {
+                return ((FeatureDescription) obj).serviceId == this.serviceId;
             }
             return false;
         }
diff --git a/src/main/java/org/apache/sling/featureflags/impl/ResourceDecoratorImpl.java b/src/main/java/org/apache/sling/featureflags/impl/FeatureResourceDecorator.java
similarity index 58%
rename from src/main/java/org/apache/sling/featureflags/impl/ResourceDecoratorImpl.java
rename to src/main/java/org/apache/sling/featureflags/impl/FeatureResourceDecorator.java
index e2f818d..4985ab0 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/ResourceDecoratorImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/FeatureResourceDecorator.java
@@ -20,46 +20,34 @@ package org.apache.sling.featureflags.impl;
 
 import javax.servlet.http.HttpServletRequest;
 
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceDecorator;
-import org.apache.sling.api.resource.ResourceWrapper;
 import org.apache.sling.featureflags.ClientContext;
 
 /**
  * Resource decorator implementing the resource type mapping
  */
-@Component
-@Service(value=ResourceDecorator.class)
-public class ResourceDecoratorImpl implements ResourceDecorator {
+public class FeatureResourceDecorator implements ResourceDecorator {
 
-    @Reference
-    private FeatureManager manager;
+    private final FeatureManager manager;
+
+    FeatureResourceDecorator(final FeatureManager manager) {
+        this.manager = manager;
+    }
 
     @Override
     public Resource decorate(final Resource resource) {
+        Resource result = resource;
         final ClientContext info = manager.getCurrentClientContext();
-        if ( info != null ) {
-            final String resourceType = resource.getResourceType();
-            final String overwriteType = ((ClientContextImpl)info).getResourceTypeMapping().get(resourceType);
-            if ( overwriteType != null ) {
-                return new ResourceWrapper(resource) {
-
-                    @Override
-                    public String getResourceType() {
-                        return overwriteType;
-                    }
-
-                    @Override
-                    public String getResourceSuperType() {
-                        return resourceType;
-                    }
-                };
+        if (info instanceof ClientContextImpl) {
+            for (ResourceDecorator rd : ((ClientContextImpl) info).getResourceDecorators()) {
+                Resource r = rd.decorate(resource);
+                if (r != null) {
+                    result = r;
+                }
             }
         }
-        return resource;
+        return result;
     }
 
     @Override
diff --git a/src/main/java/org/apache/sling/featureflags/impl/FeatureWebConsolePlugin.java b/src/main/java/org/apache/sling/featureflags/impl/FeatureWebConsolePlugin.java
new file mode 100644
index 0000000..ff2b8d7
--- /dev/null
+++ b/src/main/java/org/apache/sling/featureflags/impl/FeatureWebConsolePlugin.java
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+package org.apache.sling.featureflags.impl;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.featureflags.ExecutionContext;
+import org.apache.sling.featureflags.Feature;
+
+@SuppressWarnings("serial")
+public class FeatureWebConsolePlugin extends HttpServlet {
+
+    private final FeatureManager featureManager;
+
+    FeatureWebConsolePlugin(final FeatureManager featureManager) {
+        this.featureManager = featureManager;
+    }
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        final PrintWriter pw = resp.getWriter();
+        final Feature[] features = this.featureManager.getAvailableFeatures();
+        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 ExecutionContext ctx = createContext(req);
+            for (final Feature feature : features) {
+                pw.printf("<tr><td>%s</td><td>%s</td><td>%s</td></tr>%n", feature.getName(), feature.getDescription(),
+                    feature.isEnabled(ctx));
+            }
+            pw.println("</table>");
+        }
+    }
+
+    private ExecutionContext createContext(final HttpServletRequest req) {
+        return new ExecutionContext() {
+
+            @Override
+            public ResourceResolver getResourceResolver() {
+                return null;
+            }
+
+            @Override
+            public HttpServletRequest getRequest() {
+                return req;
+            }
+        };
+    }
+}
diff --git a/src/main/java/org/apache/sling/featureflags/impl/FeaturesImpl.java b/src/main/java/org/apache/sling/featureflags/impl/FeaturesImpl.java
index e0e836e..eb67dd6 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/FeaturesImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/FeaturesImpl.java
@@ -18,10 +18,8 @@
  */
 package org.apache.sling.featureflags.impl;
 
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.Service;
-import org.apache.sling.api.SlingHttpServletRequest;
+import javax.servlet.http.HttpServletRequest;
+
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.featureflags.ClientContext;
 import org.apache.sling.featureflags.Feature;
@@ -30,12 +28,13 @@ import org.apache.sling.featureflags.Features;
 /**
  * This is a wrapper around the internal feature manager.
  */
-@Component
-@Service(value=Features.class)
 public class FeaturesImpl implements Features {
 
-    @Reference
-    private FeatureManager manager;
+    private final FeatureManager manager;
+
+    FeaturesImpl(final FeatureManager manager) {
+        this.manager = manager;
+    }
 
     @Override
     public String[] getAvailableFeatureNames() {
@@ -68,7 +67,7 @@ public class FeaturesImpl implements Features {
     }
 
     @Override
-    public ClientContext createClientContext(final SlingHttpServletRequest request) {
+    public ClientContext createClientContext(final HttpServletRequest request) {
         return this.manager.createClientContext(request);
     }
 }
diff --git a/src/main/java/org/apache/sling/featureflags/impl/ResourceAccessImpl.java b/src/main/java/org/apache/sling/featureflags/impl/ResourceAccessImpl.java
deleted file mode 100644
index 8772cf3..0000000
--- a/src/main/java/org/apache/sling/featureflags/impl/ResourceAccessImpl.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.
- */
-package org.apache.sling.featureflags.impl;
-
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.Service;
-import org.apache.sling.api.resource.Resource;
-import org.apache.sling.featureflags.ClientContext;
-import org.apache.sling.featureflags.ResourceHiding;
-import org.apache.sling.resourceaccesssecurity.AllowingResourceAccessGate;
-import org.apache.sling.resourceaccesssecurity.ResourceAccessGate;
-
-/**
- * Resource access gate implementing the hiding of resources.
- */
-@Component
-@Service(value=ResourceAccessGate.class)
-@Property(name=ResourceAccessGate.CONTEXT, value=ResourceAccessGate.APPLICATION_CONTEXT)
-public class ResourceAccessImpl
-    extends AllowingResourceAccessGate
-    implements ResourceAccessGate {
-
-    @Reference
-    private FeatureManager manager;
-
-    @Override
-    public GateResult canRead(final Resource resource) {
-        boolean available = true;
-        final ClientContext info = manager.getCurrentClientContext();
-        if ( info != null ) {
-            for(final ResourceHiding f : ((ClientContextImpl)info).getHidingFeatures() ) {
-                available = !f.hideResource(resource);
-                if ( !available) {
-                    break;
-                }
-            }
-        }
-        return (available ? GateResult.DONTCARE : GateResult.DENIED);
-    }
-}
diff --git a/src/main/java/org/apache/sling/featureflags/package-info.java b/src/main/java/org/apache/sling/featureflags/package-info.java
index 90264d0..f1fb45b 100644
--- a/src/main/java/org/apache/sling/featureflags/package-info.java
+++ b/src/main/java/org/apache/sling/featureflags/package-info.java
@@ -18,10 +18,48 @@
  */
 
 /**
- * Provides a service to interface which may be implemented by applications
- * to get notified on cluster topology changes.
+ * The <i>Feature Flags</i> feature allows applications to dynamically
+ * provide features to clients and consumers depending on various criteria such as
+ * <ul>
+ * <li>Time of Day</li>
+ * <li>Static Configuration</li>
+ * <li>Request Parameter</li>
+ * <li>Some Resource</li>
+ * </ul>
+ * <p>
+ * Feature flag support consists of two parts: The feature flag itself represented
+ * by the {@link org.apache.sling.featureflags.Feature Feature} interface and the
+ * the application providing a feature guarded by a feature flag. Such applications
+ * make use of the {@link org.apache.sling.featureflags.Features Features} service to
+ * query feature flags.
+ * <p>
+ * Feature flags can be provided by registering
+ * {@link org.apache.sling.featureflags.Feature Feature} services. Alternatively
+ * feature flags can be provided by factory configuration with factory PID
+ * {@code org.apache.sling.featureflags.Feature} as follows:
+ * <table>
+ *  <tr>
+ *      <td>{@code name}</td>
+ *      <td>Short name of this feature. This name is used to refer to this 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>
+ *  </tr>
+ *  <tr>
+ *      <td>{@code description}</td>
+ *      <td>Description for the feature. The intent is to descibe the behaviour
+ *          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>
+ *  </tr>
+ *  <tr>
+ *      <td>{@code enabled}</td>
+ *      <td>Boolean flag indicating whether the feature is enabled or not by
+ *          this configuration</td>
+ *  </tr>
+ * </table>
  *
  * @version 1.0
+ * @see <a href="http://sling.apache.org/documentation/the-sling-engine/featureflags.html">Feature Flags</a>
  */
 @Version("1.0")
 package org.apache.sling.featureflags;

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 23/25: Add svn info, remove unused dep

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit 22dc66ad51ba5efdbe3c9e1d5b5484170f77662e
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Mon Mar 31 12:01:49 2014 +0000

    Add svn info, remove unused dep
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/feature-flags@1583307 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/pom.xml b/pom.xml
index 6ea7c84..c9fdc64 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,6 +17,12 @@
         <sling.java.version>6</sling.java.version>
     </properties>
 
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/feature-flags</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/feature-flags</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/feature-flags</url>
+    </scm>
+
     <build>
         <plugins>
             <plugin>
@@ -53,12 +59,6 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.sling</groupId>
-            <artifactId>org.apache.sling.auth.core</artifactId>
-            <version>1.1.0</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>servlet-api</artifactId>
         </dependency>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 24/25: [maven-release-plugin] prepare release org.apache.sling.featureflags-1.0.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit 8ef0dda89b53957515026b20bdcf3a82f1231ea3
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Mon Mar 31 12:08:00 2014 +0000

    [maven-release-plugin] prepare release org.apache.sling.featureflags-1.0.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/feature-flags@1583308 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index c9fdc64..a8d8025 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,7 +9,7 @@
     
     <groupId>org.apache.sling</groupId>
     <artifactId>org.apache.sling.featureflags</artifactId>
-    <version>0.0.1-SNAPSHOT</version>
+    <version>1.0.0</version>
     <packaging>bundle</packaging>
     <name>Apache Sling Feature Flags</name>
     
@@ -18,9 +18,9 @@
     </properties>
 
     <scm>
-        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/feature-flags</connection>
-        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/feature-flags</developerConnection>
-        <url>http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/feature-flags</url>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.featureflags-1.0.0</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.featureflags-1.0.0</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.featureflags-1.0.0</url>
     </scm>
 
     <build>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 21/25: FELIX-3444 : Provide a switch to enable feature flags for the resource resolver

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit 6bc6971bcab0e32d380915bb6f01789cc2567b8b
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Mon Mar 10 14:31:48 2014 +0000

    FELIX-3444 : Provide a switch to enable feature flags for the resource resolver
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/feature-flags@1575951 13f79535-47bb-0310-9956-ffa450edef68
---
 .../sling/featureflags/FeatureConstants.java       | 31 +++++++++++++
 .../FeatureAuthenticationInfoPostProcessor.java    | 52 ++++++++++++++++++++++
 2 files changed, 83 insertions(+)

diff --git a/src/main/java/org/apache/sling/featureflags/FeatureConstants.java b/src/main/java/org/apache/sling/featureflags/FeatureConstants.java
new file mode 100644
index 0000000..47b1f8b
--- /dev/null
+++ b/src/main/java/org/apache/sling/featureflags/FeatureConstants.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+package org.apache.sling.featureflags;
+
+
+public abstract class FeatureConstants {
+
+    /**
+     * The name of the resource resolver attribute which is set if the
+     * feature flag support should be enabled in the resource resolver.
+     * The value of this property should be of type Boolean. The default
+     * is <code>false</code>
+     */
+    public static final String RESOLVER_ATTR_FEATURES_ENABLED = "sling.resourceresolver.feature";
+}
diff --git a/src/main/java/org/apache/sling/featureflags/impl/FeatureAuthenticationInfoPostProcessor.java b/src/main/java/org/apache/sling/featureflags/impl/FeatureAuthenticationInfoPostProcessor.java
new file mode 100644
index 0000000..ab2f30c
--- /dev/null
+++ b/src/main/java/org/apache/sling/featureflags/impl/FeatureAuthenticationInfoPostProcessor.java
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+package org.apache.sling.featureflags.impl;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.auth.core.spi.AuthenticationInfo;
+import org.apache.sling.auth.core.spi.AuthenticationInfoPostProcessor;
+import org.apache.sling.featureflags.FeatureConstants;
+
+/**
+ * This authentication info post processor enables the feature flag support
+ * in the resource resolver for GET and HEAD requests.
+ */
+@Component
+@Service(value=AuthenticationInfoPostProcessor.class)
+public class FeatureAuthenticationInfoPostProcessor implements AuthenticationInfoPostProcessor {
+
+    /**
+     * @see org.apache.sling.auth.core.spi.AuthenticationInfoPostProcessor#postProcess(org.apache.sling.auth.core.spi.AuthenticationInfo, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+     */
+    @Override
+    public void postProcess(final AuthenticationInfo info,
+            final HttpServletRequest request,
+            final HttpServletResponse response)
+    throws LoginException {
+        if ( "GET".equals(request.getMethod()) || "HEAD".equals(request.getMethod()) ) {
+            info.put(FeatureConstants.RESOLVER_ATTR_FEATURES_ENABLED, Boolean.TRUE);
+        }
+    }
+
+}

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 02/25: Implemet hiding of resource and decorating

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit 68ee64644cd4597f0bf5b904c40a7a7dfb5e1dac
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Thu Dec 19 03:46:14 2013 +0000

    Implemet hiding of resource and decorating
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/whiteboard/feature-flags@1552222 13f79535-47bb-0310-9956-ffa450edef68
---
 .../featureflags/impl/ExecutionContextFilter.java  |   8 +-
 .../extensions/featureflags/impl/FeatureImpl.java  | 154 +--------------------
 .../impl/{FeatureImpl.java => FeatureManager.java} |  32 ++++-
 .../featureflags/impl/ResourceAccessImpl.java      |   9 +-
 ...eAccessImpl.java => ResourceDecoratorImpl.java} |  45 ++++--
 5 files changed, 75 insertions(+), 173 deletions(-)

diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/ExecutionContextFilter.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/ExecutionContextFilter.java
index 7ee7b85..8103bc4 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/ExecutionContextFilter.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/ExecutionContextFilter.java
@@ -19,8 +19,9 @@
 package org.apache.sling.extensions.featureflags.impl;
 
 import java.io.IOException;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
@@ -85,7 +86,7 @@ public class ExecutionContextFilter implements Filter {
     public final class ExecutionContextInfo {
 
         public final ExecutionContext context;
-        public final Set<String> enabledFeatures = new HashSet<String>();
+        public final List<String> enabledFeatures = new ArrayList<String>();
 
         public ExecutionContextInfo(final SlingHttpServletRequest req,
                 final Feature feature) {
@@ -95,6 +96,7 @@ public class ExecutionContextFilter implements Filter {
                     enabledFeatures.add(name);
                 }
             }
+            Collections.sort(enabledFeatures);
         }
     }
 }
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureImpl.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureImpl.java
index 65abe86..b42dca9 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureImpl.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureImpl.java
@@ -18,21 +18,12 @@
  */
 package org.apache.sling.extensions.featureflags.impl;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.apache.felix.scr.annotations.ReferencePolicy;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.extensions.featureflags.ExecutionContext;
 import org.apache.sling.extensions.featureflags.Feature;
 import org.apache.sling.extensions.featureflags.FeatureProvider;
-import org.osgi.framework.Constants;
 
 /**
  * This service implements the feature handling.
@@ -40,157 +31,24 @@ import org.osgi.framework.Constants;
  */
 @Component
 @Service(value=Feature.class)
-@Reference(name="featureProvider",
-           cardinality=ReferenceCardinality.OPTIONAL_MULTIPLE,
-           policy=ReferencePolicy.DYNAMIC,
-           referenceInterface=FeatureProvider.class)
 public class FeatureImpl implements Feature {
 
-    private final Map<String, List<FeatureProviderDescription>> providers = new HashMap<String, List<FeatureProviderDescription>>();
-
-    private Map<String, FeatureProviderDescription> activeProviders = new HashMap<String, FeatureProviderDescription>();
-
-    /**
-     * Bind a new feature provider
-     */
-    protected void bindFeatureProvider(final FeatureProvider provider, final Map<String, Object> props) {
-        final String[] features = provider.getFeatureNames();
-        if ( features != null && features.length > 0 ) {
-            final FeatureProviderDescription info = new FeatureProviderDescription(provider, props);
-            synchronized ( this.providers ) {
-                boolean changed = false;
-                for(final String n : features) {
-                    if ( n != null ) {
-                        final String name = n.trim();
-                        if ( name.length() > 0 ) {
-                            List<FeatureProviderDescription> candidates = this.providers.get(name);
-                            if ( candidates == null ) {
-                                candidates = new ArrayList<FeatureProviderDescription>();
-                                this.providers.put(name, candidates);
-                            }
-                            candidates.add(info);
-                            Collections.sort(candidates);
-                            changed = true;
-                        }
-                    }
-                }
-                if ( changed ) {
-                    this.calculateActiveProviders();
-                }
-            }
-        }
-    }
-
-    /**
-     * Unbind a feature provider
-     */
-    protected void unbindFeatureProvider(final FeatureProvider provider, final Map<String, Object> props) {
-        final String[] features = provider.getFeatureNames();
-        if ( features != null && features.length > 0 ) {
-            final FeatureProviderDescription info = new FeatureProviderDescription(provider, props);
-            synchronized ( this.providers ) {
-                boolean changed = false;
-                for(final String n : features) {
-                    if ( n != null ) {
-                        final String name = n.trim();
-                        if ( name.length() > 0 ) {
-                            final List<FeatureProviderDescription> candidates = this.providers.get(name);
-                            if ( candidates != null ) { // sanity check
-                                candidates.remove(info);
-                                if ( candidates.size() == 0 ) {
-                                    this.providers.remove(name);
-                                    changed = true;
-                                }
-                            }
-                        }
-                    }
-                }
-                if ( changed ) {
-                    this.calculateActiveProviders();
-                }
-            }
-        }
-    }
-
-    private void calculateActiveProviders() {
-        final Map<String, FeatureProviderDescription> activeMap = new HashMap<String, FeatureImpl.FeatureProviderDescription>();
-        for(final Map.Entry<String, List<FeatureProviderDescription>> entry : this.providers.entrySet()) {
-            activeMap.put(entry.getKey(), entry.getValue().get(0));
-        }
-        this.activeProviders = activeMap;
-    }
+    @Reference
+    private FeatureManager manager;
 
     @Override
     public boolean isEnabled(final String featureName, final ExecutionContext context) {
-        boolean result = false;
-        final FeatureProviderDescription desc = this.activeProviders.get(featureName);
-        if ( desc != null ) {
-            final FeatureProvider prod = desc.getProvider();
-            result = prod.isEnabled(featureName, context);
-        }
-        return result;
+        return this.manager.isEnabled(featureName, context);
     }
 
     @Override
     public String[] getFeatureNames() {
-        return this.activeProviders.keySet().toArray(new String[this.activeProviders.size()]);
+        return this.manager.getFeatureNames();
     }
 
     @Override
     public boolean isAvailable(final String featureName) {
-        return this.activeProviders.containsKey(featureName);
-    }
-
-
-    /**
-     * Internal class caching some provider infos like service id and ranking.
-     */
-    private final static class FeatureProviderDescription implements Comparable<FeatureProviderDescription> {
-
-        public FeatureProvider provider;
-        public final int ranking;
-        public final long serviceId;
-
-        public FeatureProviderDescription(final FeatureProvider provider, final Map<String, Object> props) {
-            this.provider = provider;
-            final Object sr = props.get(Constants.SERVICE_RANKING);
-            if ( sr == null || !(sr instanceof Integer)) {
-                this.ranking = 0;
-            } else {
-                this.ranking = (Integer)sr;
-            }
-            this.serviceId = (Long)props.get(Constants.SERVICE_ID);
-        }
-
-        @Override
-        public int compareTo(final FeatureProviderDescription o) {
-            if ( this.ranking < o.ranking ) {
-                return 1;
-            } else if (this.ranking > o.ranking ) {
-                return -1;
-            }
-            // If ranks are equal, then sort by service id in descending order.
-            return (this.serviceId < o.serviceId) ? -1 : 1;
-        }
-
-        @Override
-        public boolean equals(final Object obj) {
-            if ( obj instanceof FeatureProviderDescription ) {
-                return ((FeatureProviderDescription)obj).serviceId == this.serviceId;
-            }
-            return false;
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + (int) (serviceId ^ (serviceId >>> 32));
-            return result;
-        }
-
-        public FeatureProvider getProvider() {
-            return provider;
-        }
+        // TODO Auto-generated method stub
+        return this.manager.isAvailable(featureName);
     }
 }
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureImpl.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureManager.java
similarity index 85%
copy from src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureImpl.java
copy to src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureManager.java
index 65abe86..dad36fe 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureImpl.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureManager.java
@@ -28,7 +28,7 @@ import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.ReferencePolicy;
-import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.resource.Resource;
 import org.apache.sling.extensions.featureflags.ExecutionContext;
 import org.apache.sling.extensions.featureflags.Feature;
 import org.apache.sling.extensions.featureflags.FeatureProvider;
@@ -39,12 +39,11 @@ import org.osgi.framework.Constants;
  * It keeps track of all {@link FeatureProvider} services.
  */
 @Component
-@Service(value=Feature.class)
 @Reference(name="featureProvider",
            cardinality=ReferenceCardinality.OPTIONAL_MULTIPLE,
            policy=ReferencePolicy.DYNAMIC,
            referenceInterface=FeatureProvider.class)
-public class FeatureImpl implements Feature {
+public class FeatureManager implements Feature {
 
     private final Map<String, List<FeatureProviderDescription>> providers = new HashMap<String, List<FeatureProviderDescription>>();
 
@@ -113,7 +112,7 @@ public class FeatureImpl implements Feature {
     }
 
     private void calculateActiveProviders() {
-        final Map<String, FeatureProviderDescription> activeMap = new HashMap<String, FeatureImpl.FeatureProviderDescription>();
+        final Map<String, FeatureProviderDescription> activeMap = new HashMap<String, FeatureManager.FeatureProviderDescription>();
         for(final Map.Entry<String, List<FeatureProviderDescription>> entry : this.providers.entrySet()) {
             activeMap.put(entry.getKey(), entry.getValue().get(0));
         }
@@ -141,6 +140,19 @@ public class FeatureImpl implements Feature {
         return this.activeProviders.containsKey(featureName);
     }
 
+    /**
+     * Checks whether a resource should be hidden for a feature.
+     * This check is only executed if {@link #isEnabled(String, ExecutionContext)}
+     * return true for the given feature/context.
+     */
+    public boolean hideResource(final String featureName, final Resource resource) {
+        final FeatureProviderDescription desc = this.activeProviders.get(featureName);
+        if ( desc != null ) {
+            final FeatureProvider prod = desc.getProvider();
+            return prod.hideResource(featureName, resource);
+        }
+        return false;
+    }
 
     /**
      * Internal class caching some provider infos like service id and ranking.
@@ -193,4 +205,16 @@ public class FeatureImpl implements Feature {
             return provider;
         }
     }
+
+    public String getResourceType(final String featureName, final String resourceType) {
+        final FeatureProviderDescription desc = this.activeProviders.get(featureName);
+        if ( desc != null ) {
+            final FeatureProvider prod = desc.getProvider();
+            final Map<String, String> mapping = prod.getResourceTypeMapping(featureName);
+            if ( mapping != null ) {
+                return mapping.get(resourceType);
+            }
+        }
+        return null;
+    }
 }
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceAccessImpl.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceAccessImpl.java
index a3bed50..5840a3a 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceAccessImpl.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceAccessImpl.java
@@ -22,7 +22,6 @@ import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.resource.Resource;
-import org.apache.sling.extensions.featureflags.Feature;
 import org.apache.sling.resourceaccesssecurity.AllowingResourceAccessGate;
 import org.apache.sling.resourceaccesssecurity.ResourceAccessGate;
 
@@ -33,7 +32,7 @@ public class ResourceAccessImpl
     implements ResourceAccessGate {
 
     @Reference
-    private Feature feature;
+    private FeatureManager manager;
 
     @Override
     public GateResult canRead(final Resource resource) {
@@ -42,8 +41,10 @@ public class ResourceAccessImpl
         if ( info != null ) {
             for(final String name : info.enabledFeatures) {
                 // we can't check as Feature does not have the api (TODO - we deny for now)
-                available = false;
-                break;
+                available = !manager.hideResource(name, resource);
+                if ( !available) {
+                    break;
+                }
             }
         }
         return (available ? GateResult.DONTCARE : GateResult.DENIED);
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceAccessImpl.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceDecoratorImpl.java
similarity index 53%
copy from src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceAccessImpl.java
copy to src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceDecoratorImpl.java
index a3bed50..5d2cbad 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceAccessImpl.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceDecoratorImpl.java
@@ -18,34 +18,51 @@
  */
 package org.apache.sling.extensions.featureflags.impl;
 
+import javax.servlet.http.HttpServletRequest;
+
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.resource.Resource;
-import org.apache.sling.extensions.featureflags.Feature;
-import org.apache.sling.resourceaccesssecurity.AllowingResourceAccessGate;
-import org.apache.sling.resourceaccesssecurity.ResourceAccessGate;
+import org.apache.sling.api.resource.ResourceDecorator;
+import org.apache.sling.api.resource.ResourceWrapper;
 
 @Component
-@Service(value=ResourceAccessGate.class)
-public class ResourceAccessImpl
-    extends AllowingResourceAccessGate
-    implements ResourceAccessGate {
+@Service(value=ResourceDecorator.class)
+public class ResourceDecoratorImpl implements ResourceDecorator {
 
     @Reference
-    private Feature feature;
+    private FeatureManager manager;
 
     @Override
-    public GateResult canRead(final Resource resource) {
-        boolean available = true;
+    public Resource decorate(final Resource resource) {
         final ExecutionContextFilter.ExecutionContextInfo info = ExecutionContextFilter.getCurrentExecutionContextInfo();
         if ( info != null ) {
             for(final String name : info.enabledFeatures) {
-                // we can't check as Feature does not have the api (TODO - we deny for now)
-                available = false;
-                break;
+
+                final String resourceType = resource.getResourceType();
+                final String overwriteType = manager.getResourceType(name, resourceType);
+                if ( overwriteType != null ) {
+                    return new ResourceWrapper(resource) {
+
+                        @Override
+                        public String getResourceType() {
+                            return overwriteType;
+                        }
+
+                        @Override
+                        public String getResourceSuperType() {
+                            return resourceType;
+                        }
+                    };
+                }
             }
         }
-        return (available ? GateResult.DONTCARE : GateResult.DENIED);
+        return resource;
+    }
+
+    @Override
+    public Resource decorate(final Resource resource, final HttpServletRequest request) {
+        return this.decorate(resource);
     }
 }

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 25/25: [maven-release-plugin] copy for tag org.apache.sling.featureflags-1.0.0

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit f839000e8a933f6fad69c32aff209bacb9048599
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Mon Mar 31 12:08:36 2014 +0000

    [maven-release-plugin]  copy for tag org.apache.sling.featureflags-1.0.0
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.featureflags-1.0.0@1583309 13f79535-47bb-0310-9956-ffa450edef68

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 05/25: Update javadocs

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit d262cb347a7df51681dfd8719cd797a4882042b9
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Thu Dec 19 09:53:17 2013 +0000

    Update javadocs
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/whiteboard/feature-flags@1552268 13f79535-47bb-0310-9956-ffa450edef68
---
 .../apache/sling/extensions/featureflags/FeatureProvider.java  | 10 ++++++++--
 .../org/apache/sling/extensions/featureflags/Features.java     |  5 +++--
 .../sling/extensions/featureflags/impl/FeatureManager.java     |  2 +-
 .../sling/extensions/featureflags/impl/FeaturesImpl.java       |  4 ++--
 4 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/src/main/java/org/apache/sling/extensions/featureflags/FeatureProvider.java b/src/main/java/org/apache/sling/extensions/featureflags/FeatureProvider.java
index fad43bc..2c8c7c6 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/FeatureProvider.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/FeatureProvider.java
@@ -44,14 +44,20 @@ public interface FeatureProvider {
     /**
      * Returns the resource type mapping for a feature.
      * This mapping is only used if {@link #isEnabled(String, ExecutionContext)}
-     * return true for the given feature/context.
+     * return true for the given feature/context. The caller of this
+     * method must ensure to call {@link #isEnabled(String, ExecutionContext)}
+     * before calling this method and only call this method if
+     * {@link #isEnabled(String, ExecutionContext)} return <code>true</code>
      */
     Map<String, String> getResourceTypeMapping(String featureName);
 
     /**
      * Checks whether a resource should be hidden for a feature.
      * This check is only executed if {@link #isEnabled(String, ExecutionContext)}
-     * return true for the given feature/context.
+     * return true for the given feature/context. The caller of this
+     * method must ensure to call {@link #isEnabled(String, ExecutionContext)}
+     * before calling this method and only call this method if
+     * {@link #isEnabled(String, ExecutionContext)} return <code>true</code>
      */
     boolean hideResource(String featureName, Resource resource);
 }
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/Features.java b/src/main/java/org/apache/sling/extensions/featureflags/Features.java
index f955039..28af24d 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/Features.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/Features.java
@@ -32,9 +32,10 @@ import aQute.bnd.annotation.ProviderType;
 public interface Features {
 
     /**
-     * Get the list of all active features
+     * Get the list of all available features. A feature is available
+     * if there is a {@link FeatureProvider}
      */
-    String[] getFeatureNames();
+    String[] getAvailableFeatureNames();
 
     /**
      * Checks whether a feature with the given name is available.
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureManager.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureManager.java
index 4d42d0a..38fac8a 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureManager.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureManager.java
@@ -175,7 +175,7 @@ public class FeatureManager implements Features {
     }
 
     @Override
-    public String[] getFeatureNames() {
+    public String[] getAvailableFeatureNames() {
         return this.activeProviders.keySet().toArray(new String[this.activeProviders.size()]);
     }
 
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeaturesImpl.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/FeaturesImpl.java
index 5c8bd1a..75ef89f 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeaturesImpl.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/FeaturesImpl.java
@@ -37,8 +37,8 @@ public class FeaturesImpl implements Features {
     private FeatureManager manager;
 
     @Override
-    public String[] getFeatureNames() {
-        return this.manager.getFeatureNames();
+    public String[] getAvailableFeatureNames() {
+        return this.manager.getAvailableFeatureNames();
     }
 
     @Override

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 15/25: SLING-3148 Set appropriate label for the configuration metatype

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit b5e22fe696e2eb731c621e9341e2c1e5fd7ae2c7
Author: Felix Meschberger <fm...@apache.org>
AuthorDate: Tue Jan 28 08:44:13 2014 +0000

    SLING-3148 Set appropriate label for the configuration metatype
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/feature-flags@1562005 13f79535-47bb-0310-9956-ffa450edef68
---
 src/main/java/org/apache/sling/featureflags/impl/ConfiguredFeature.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/java/org/apache/sling/featureflags/impl/ConfiguredFeature.java b/src/main/java/org/apache/sling/featureflags/impl/ConfiguredFeature.java
index 1f4db86..d79d8cf 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/ConfiguredFeature.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/ConfiguredFeature.java
@@ -37,7 +37,7 @@ import org.osgi.framework.Constants;
         metatype = true,
         configurationFactory = true,
         policy = ConfigurationPolicy.REQUIRE,
-        label = "Statically Configured Feature",
+        label = "Apache Sling Configured Feature",
         description = "Allows for the definition of statically configured features which are defined and enabled through OSGi configuration")
 @Service
 public class ConfiguredFeature implements Feature {

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 03/25: Take II for the feature flags, separate into different contexts to avoid duplicate evaluation

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit 93f4097f4c7f1da4e4dff44216767f38998fdef0
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Thu Dec 19 04:47:20 2013 +0000

    Take II for the feature flags, separate into different contexts to avoid duplicate evaluation
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/whiteboard/feature-flags@1552225 13f79535-47bb-0310-9956-ffa450edef68
---
 .../{Feature.java => ClientContext.java}           | 33 +++------
 .../extensions/featureflags/FeatureProvider.java   |  2 +-
 .../featureflags/{Feature.java => Features.java}   | 40 ++++++-----
 .../{Feature.java => ProviderContext.java}         | 35 ++++-----
 .../featureflags/impl/ClientContextImpl.java       | 60 ++++++++++++++++
 ...Filter.java => CurrentClientContextFilter.java} | 57 ++++-----------
 .../FeatureContextImpl.java}                       | 20 ++----
 .../featureflags/impl/FeatureManager.java          | 82 ++++++++++++++++------
 .../impl/{FeatureImpl.java => FeaturesImpl.java}   | 35 +++++----
 .../featureflags/impl/ResourceAccessImpl.java      |  9 ++-
 .../featureflags/impl/ResourceDecoratorImpl.java   |  8 ++-
 11 files changed, 225 insertions(+), 156 deletions(-)

diff --git a/src/main/java/org/apache/sling/extensions/featureflags/Feature.java b/src/main/java/org/apache/sling/extensions/featureflags/ClientContext.java
similarity index 54%
copy from src/main/java/org/apache/sling/extensions/featureflags/Feature.java
copy to src/main/java/org/apache/sling/extensions/featureflags/ClientContext.java
index ed901c5..d44387b 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/Feature.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/ClientContext.java
@@ -18,37 +18,26 @@
  */
 package org.apache.sling.extensions.featureflags;
 
+import java.util.Collection;
+
 import aQute.bnd.annotation.ProviderType;
 
 /**
- * The feature service is the central gateway for feature handling.
- * It can be used to query the available features and to
- * check whether a feature is enabled for the current execution
- * context.
+ * The client context can be used by client code to check whether
+ * a specific feature is enable.
+ * A client context can be created through the {@link Features} service.
  */
 @ProviderType
-public interface Feature {
-
+public interface ClientContext {
 
     /**
-     * Checks whether the feature is enabled for the given
-     * execution context.
-     *
-     * The actual check is delegated to the {@link FeatureProvider}
-     * providing the feature.
+     * Returns <code>true</code> if the feature is enabled.
      */
-    boolean isEnabled(String featureName, ExecutionContext context);
-
-    /** Get the list of active feature flags */
-    String[] getFeatureNames();
+    boolean isEnabled(String featureName);
 
     /**
-     * Checks whether a feature with the given name is available.
-     * A feature is available if there is a {@link FeatureProvider}
-     * for that feature.
-     * @param featureName
-     * @return
+     * Returns a list of all enabled features
+     * @return The list of features, the list might be empty.
      */
-    boolean isAvailable(String featureName);
-
+    Collection<String> getEnabledFeatures();
 }
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/FeatureProvider.java b/src/main/java/org/apache/sling/extensions/featureflags/FeatureProvider.java
index 66264b9..fad43bc 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/FeatureProvider.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/FeatureProvider.java
@@ -34,7 +34,7 @@ public interface FeatureProvider {
      * Checks whether the feature is enabled for the current execution
      * context.
      */
-    boolean isEnabled(String featureName, ExecutionContext context);
+    boolean isEnabled(String featureName, ProviderContext context);
 
     /**
      * Return the list of available features from this provider.
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/Feature.java b/src/main/java/org/apache/sling/extensions/featureflags/Features.java
similarity index 57%
copy from src/main/java/org/apache/sling/extensions/featureflags/Feature.java
copy to src/main/java/org/apache/sling/extensions/featureflags/Features.java
index ed901c5..f955039 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/Feature.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/Features.java
@@ -18,37 +18,45 @@
  */
 package org.apache.sling.extensions.featureflags;
 
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.ResourceResolver;
+
 import aQute.bnd.annotation.ProviderType;
 
 /**
- * The feature service is the central gateway for feature handling.
- * It can be used to query the available features and to
- * check whether a feature is enabled for the current execution
- * context.
+ * 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.
  */
 @ProviderType
-public interface Feature {
-
+public interface Features {
 
     /**
-     * Checks whether the feature is enabled for the given
-     * execution context.
-     *
-     * The actual check is delegated to the {@link FeatureProvider}
-     * providing the feature.
+     * Get the list of all active features
      */
-    boolean isEnabled(String featureName, ExecutionContext context);
-
-    /** Get the list of active feature flags */
     String[] getFeatureNames();
 
     /**
      * Checks whether a feature with the given name is available.
      * A feature is available if there is a {@link FeatureProvider}
      * for that feature.
-     * @param featureName
-     * @return
      */
     boolean isAvailable(String featureName);
 
+    /**
+     * Returns the current client context, if available
+     */
+    ClientContext getCurrentClientContext();
+
+    /**
+     * Create a client context for the resource resolver.
+     * @throws IllegalArgumentException If resolver is null
+     */
+    ClientContext createClientContext(ResourceResolver resolver);
+
+    /**
+     * Create a client context for the request.
+     * @throws IllegalArgumentException If request is null
+     */
+    ClientContext createClientContext(SlingHttpServletRequest request);
 }
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/Feature.java b/src/main/java/org/apache/sling/extensions/featureflags/ProviderContext.java
similarity index 54%
rename from src/main/java/org/apache/sling/extensions/featureflags/Feature.java
rename to src/main/java/org/apache/sling/extensions/featureflags/ProviderContext.java
index ed901c5..8af8a8c 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/Feature.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/ProviderContext.java
@@ -18,37 +18,28 @@
  */
 package org.apache.sling.extensions.featureflags;
 
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.ResourceResolver;
+
 import aQute.bnd.annotation.ProviderType;
 
 /**
- * The feature service is the central gateway for feature handling.
- * It can be used to query the available features and to
- * check whether a feature is enabled for the current execution
- * context.
+ * The provider context contains all information that is passed to a
+ * {@link FeatureProvider} in order to check whether a feature
+ * is enabled.
  */
 @ProviderType
-public interface Feature {
-
+public interface ProviderContext {
 
     /**
-     * Checks whether the feature is enabled for the given
-     * execution context.
-     *
-     * The actual check is delegated to the {@link FeatureProvider}
-     * providing the feature.
+     * Return the associated request if available
+     * @return the request or <code>null</code>
      */
-    boolean isEnabled(String featureName, ExecutionContext context);
-
-    /** Get the list of active feature flags */
-    String[] getFeatureNames();
+    SlingHttpServletRequest getRequest();
 
     /**
-     * Checks whether a feature with the given name is available.
-     * A feature is available if there is a {@link FeatureProvider}
-     * for that feature.
-     * @param featureName
-     * @return
+     * Return the associated resource resolver.
+     * @return the resource resolver
      */
-    boolean isAvailable(String featureName);
-
+    ResourceResolver getResourceResolver();
 }
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/ClientContextImpl.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/ClientContextImpl.java
new file mode 100644
index 0000000..b4228e3
--- /dev/null
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/ClientContextImpl.java
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+package org.apache.sling.extensions.featureflags.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.sling.extensions.featureflags.ClientContext;
+import org.apache.sling.extensions.featureflags.ProviderContext;
+
+/**
+ * Implementation of the client context
+ */
+public class ClientContextImpl implements ClientContext {
+
+    private final ProviderContext featureContext;
+
+    private final List<String> enabledFeatures = new ArrayList<String>();
+
+    public ClientContextImpl(final ProviderContext featureContext) {
+        this.featureContext = featureContext;
+    }
+
+    public void addFeature(final String name) {
+        this.enabledFeatures.add(name);
+        Collections.sort(this.enabledFeatures);
+    }
+
+    public ProviderContext getFeatureContext() {
+        return this.featureContext;
+    }
+
+    @Override
+    public boolean isEnabled(final String featureName) {
+        return this.enabledFeatures.contains(featureName);
+    }
+
+    @Override
+    public Collection<String> getEnabledFeatures() {
+        return this.enabledFeatures;
+    }
+}
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/ExecutionContextFilter.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/CurrentClientContextFilter.java
similarity index 52%
rename from src/main/java/org/apache/sling/extensions/featureflags/impl/ExecutionContextFilter.java
rename to src/main/java/org/apache/sling/extensions/featureflags/impl/CurrentClientContextFilter.java
index 8103bc4..349538f 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/ExecutionContextFilter.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/CurrentClientContextFilter.java
@@ -19,9 +19,6 @@
 package org.apache.sling.extensions.featureflags.impl;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
 
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
@@ -35,68 +32,40 @@ import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.SlingHttpServletRequest;
-import org.apache.sling.extensions.featureflags.ExecutionContext;
-import org.apache.sling.extensions.featureflags.Feature;
 
+/**
+ * This general servlet filter sets the current client context to the
+ * current request.
+ */
 @Component
 @Service(value=Filter.class)
 @Property(name="pattern", value="/.*")
-public class ExecutionContextFilter implements Filter {
-
-    private static ThreadLocal<ExecutionContextInfo> EXECUTION_CONTEXT;
+public class CurrentClientContextFilter implements Filter {
 
     @Reference
-    private Feature feature;
-
-    public static ExecutionContextInfo getCurrentExecutionContextInfo() {
-        final ThreadLocal<ExecutionContextInfo> local = EXECUTION_CONTEXT;
-        if ( local != null ) {
-            return local.get();
-        }
-        return null;
-    }
-
-    @Override
-    public void destroy() {
-        EXECUTION_CONTEXT = null;
-    }
+    private FeatureManager manager;
 
     @Override
     public void doFilter(final ServletRequest req, final ServletResponse res,
             final FilterChain chain)
     throws IOException, ServletException {
-        final ThreadLocal<ExecutionContextInfo> local = EXECUTION_CONTEXT;
-        if ( local != null && req instanceof SlingHttpServletRequest ) {
-            local.set(new ExecutionContextInfo((SlingHttpServletRequest)req, feature));
+        if ( req instanceof SlingHttpServletRequest ) {
+            manager.setCurrentClientContext((SlingHttpServletRequest)req);
         }
         try {
             chain.doFilter(req, res);
         } finally {
-            if ( local != null && req instanceof SlingHttpServletRequest ) {
-                local.set(null);
-            }
+            manager.unsetCurrentClientContext();
         }
     }
 
     @Override
     public void init(final FilterConfig config) throws ServletException {
-        EXECUTION_CONTEXT = new ThreadLocal<ExecutionContextInfo>();
+        // nothing to do
     }
 
-    public final class ExecutionContextInfo {
-
-        public final ExecutionContext context;
-        public final List<String> enabledFeatures = new ArrayList<String>();
-
-        public ExecutionContextInfo(final SlingHttpServletRequest req,
-                final Feature feature) {
-            this.context = ExecutionContext.fromRequest(req);
-            for(final String name : feature.getFeatureNames()) {
-                if ( feature.isEnabled(name, context) ) {
-                    enabledFeatures.add(name);
-                }
-            }
-            Collections.sort(enabledFeatures);
-        }
+    @Override
+    public void destroy() {
+        // nothing to do
     }
 }
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/ExecutionContext.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureContextImpl.java
similarity index 72%
rename from src/main/java/org/apache/sling/extensions/featureflags/ExecutionContext.java
rename to src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureContextImpl.java
index 8e00dfd..e31dc15 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/ExecutionContext.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureContextImpl.java
@@ -16,40 +16,34 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.extensions.featureflags;
+package org.apache.sling.extensions.featureflags.impl;
 
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.extensions.featureflags.ProviderContext;
 
-public class ExecutionContext {
+public class FeatureContextImpl implements ProviderContext {
 
     private final ResourceResolver resourceResolver;
 
     private final SlingHttpServletRequest request;
 
-    public static ExecutionContext fromRequest(final SlingHttpServletRequest request) {
-        return new ExecutionContext(request);
-    }
-
-    public static ExecutionContext fromResourceResolver(final ResourceResolver resourceResolver) {
-        return new ExecutionContext(resourceResolver);
-    }
-
-    private ExecutionContext(final ResourceResolver resourceResolver) {
+    public FeatureContextImpl(final ResourceResolver resourceResolver) {
         this.request = null;
         this.resourceResolver = resourceResolver;
     }
 
-
-    private ExecutionContext(final SlingHttpServletRequest request) {
+    public FeatureContextImpl(final SlingHttpServletRequest request) {
         this.request = request;
         this.resourceResolver = request.getResourceResolver();
     }
 
+    @Override
     public SlingHttpServletRequest getRequest() {
         return this.request;
     }
 
+    @Override
     public ResourceResolver getResourceResolver() {
         return this.resourceResolver;
     }
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureManager.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureManager.java
index dad36fe..2fbf286 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureManager.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureManager.java
@@ -28,10 +28,13 @@ import org.apache.felix.scr.annotations.Component;
 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.SlingHttpServletRequest;
 import org.apache.sling.api.resource.Resource;
-import org.apache.sling.extensions.featureflags.ExecutionContext;
-import org.apache.sling.extensions.featureflags.Feature;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.extensions.featureflags.ClientContext;
+import org.apache.sling.extensions.featureflags.ProviderContext;
 import org.apache.sling.extensions.featureflags.FeatureProvider;
+import org.apache.sling.extensions.featureflags.Features;
 import org.osgi.framework.Constants;
 
 /**
@@ -43,11 +46,11 @@ import org.osgi.framework.Constants;
            cardinality=ReferenceCardinality.OPTIONAL_MULTIPLE,
            policy=ReferencePolicy.DYNAMIC,
            referenceInterface=FeatureProvider.class)
-public class FeatureManager implements Feature {
+public class FeatureManager implements Features {
 
     private final Map<String, List<FeatureProviderDescription>> providers = new HashMap<String, List<FeatureProviderDescription>>();
 
-    private Map<String, FeatureProviderDescription> activeProviders = new HashMap<String, FeatureProviderDescription>();
+    private Map<String, FeatureProvider> activeProviders = new HashMap<String, FeatureProvider>();
 
     /**
      * Bind a new feature provider
@@ -112,22 +115,63 @@ public class FeatureManager implements Feature {
     }
 
     private void calculateActiveProviders() {
-        final Map<String, FeatureProviderDescription> activeMap = new HashMap<String, FeatureManager.FeatureProviderDescription>();
+        final Map<String, FeatureProvider> activeMap = new HashMap<String, FeatureProvider>();
         for(final Map.Entry<String, List<FeatureProviderDescription>> entry : this.providers.entrySet()) {
-            activeMap.put(entry.getKey(), entry.getValue().get(0));
+            activeMap.put(entry.getKey(), entry.getValue().get(0).getProvider());
         }
         this.activeProviders = activeMap;
     }
 
+    private final ThreadLocal<ClientContextImpl> perThreadClientContext = new ThreadLocal<ClientContextImpl>();
+
+    @Override
+    public ClientContext getCurrentClientContext() {
+        return perThreadClientContext.get();
+    }
+
+    public void setCurrentClientContext(final SlingHttpServletRequest request) {
+        final ProviderContext featureContext = new FeatureContextImpl(request);
+        final ClientContextImpl ctx = this.createClientContext(featureContext);
+        perThreadClientContext.set(ctx);
+    }
+
+    public void unsetCurrentClientContext() {
+        perThreadClientContext.remove();
+    }
+
     @Override
-    public boolean isEnabled(final String featureName, final ExecutionContext context) {
-        boolean result = false;
-        final FeatureProviderDescription desc = this.activeProviders.get(featureName);
-        if ( desc != null ) {
-            final FeatureProvider prod = desc.getProvider();
-            result = prod.isEnabled(featureName, context);
+    public ClientContext createClientContext(final ResourceResolver resolver) {
+        if ( resolver == null ) {
+            throw new IllegalArgumentException("Resolver must not be null.");
         }
-        return result;
+        final ProviderContext featureContext = new FeatureContextImpl(resolver);
+        final ClientContext ctx = this.createClientContext(featureContext);
+        return ctx;
+    }
+
+    @Override
+    public ClientContext createClientContext(final SlingHttpServletRequest request) {
+        if ( request == null ) {
+            throw new IllegalArgumentException("Request must not be null.");
+        }
+        final ProviderContext featureContext = new FeatureContextImpl(request);
+        final ClientContext ctx = this.createClientContext(featureContext);
+        return ctx;
+    }
+
+    private ClientContextImpl createClientContext(final ProviderContext featureContext) {
+        final ClientContextImpl ctx = new ClientContextImpl(featureContext);
+
+        for(final Map.Entry<String, FeatureProvider> entry : this.activeProviders.entrySet()) {
+            final String name = entry.getKey();
+            final FeatureProvider provider = entry.getValue();
+
+            if ( provider.isEnabled(name, featureContext) ) {
+                ctx.addFeature(name);
+            }
+        }
+
+        return ctx;
     }
 
     @Override
@@ -142,13 +186,12 @@ public class FeatureManager implements Feature {
 
     /**
      * Checks whether a resource should be hidden for a feature.
-     * This check is only executed if {@link #isEnabled(String, ExecutionContext)}
+     * This check is only executed if {@link #isEnabled(String, ClientContext)}
      * return true for the given feature/context.
      */
     public boolean hideResource(final String featureName, final Resource resource) {
-        final FeatureProviderDescription desc = this.activeProviders.get(featureName);
-        if ( desc != null ) {
-            final FeatureProvider prod = desc.getProvider();
+        final FeatureProvider prod = this.activeProviders.get(featureName);
+        if ( prod != null ) {
             return prod.hideResource(featureName, resource);
         }
         return false;
@@ -207,9 +250,8 @@ public class FeatureManager implements Feature {
     }
 
     public String getResourceType(final String featureName, final String resourceType) {
-        final FeatureProviderDescription desc = this.activeProviders.get(featureName);
-        if ( desc != null ) {
-            final FeatureProvider prod = desc.getProvider();
+        final FeatureProvider prod = this.activeProviders.get(featureName);
+        if ( prod != null ) {
             final Map<String, String> mapping = prod.getResourceTypeMapping(featureName);
             if ( mapping != null ) {
                 return mapping.get(resourceType);
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureImpl.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/FeaturesImpl.java
similarity index 62%
rename from src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureImpl.java
rename to src/main/java/org/apache/sling/extensions/featureflags/impl/FeaturesImpl.java
index b42dca9..5c8bd1a 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureImpl.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/FeaturesImpl.java
@@ -21,34 +21,43 @@ package org.apache.sling.extensions.featureflags.impl;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
-import org.apache.sling.extensions.featureflags.ExecutionContext;
-import org.apache.sling.extensions.featureflags.Feature;
-import org.apache.sling.extensions.featureflags.FeatureProvider;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.extensions.featureflags.ClientContext;
+import org.apache.sling.extensions.featureflags.Features;
 
 /**
- * This service implements the feature handling.
- * It keeps track of all {@link FeatureProvider} services.
+ * This is a wrapper around the internal feature manager.
  */
 @Component
-@Service(value=Feature.class)
-public class FeatureImpl implements Feature {
+@Service(value=Features.class)
+public class FeaturesImpl implements Features {
 
     @Reference
     private FeatureManager manager;
 
     @Override
-    public boolean isEnabled(final String featureName, final ExecutionContext context) {
-        return this.manager.isEnabled(featureName, context);
-    }
-
-    @Override
     public String[] getFeatureNames() {
         return this.manager.getFeatureNames();
     }
 
     @Override
     public boolean isAvailable(final String featureName) {
-        // TODO Auto-generated method stub
         return this.manager.isAvailable(featureName);
     }
+
+    @Override
+    public ClientContext getCurrentClientContext() {
+        return this.manager.getCurrentClientContext();
+    }
+
+    @Override
+    public ClientContext createClientContext(final ResourceResolver resolver) {
+        return this.manager.createClientContext(resolver);
+    }
+
+    @Override
+    public ClientContext createClientContext(final SlingHttpServletRequest request) {
+        return this.manager.createClientContext(request);
+    }
 }
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceAccessImpl.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceAccessImpl.java
index 5840a3a..befc1c1 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceAccessImpl.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceAccessImpl.java
@@ -22,9 +22,13 @@ import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.resource.Resource;
+import org.apache.sling.extensions.featureflags.ClientContext;
 import org.apache.sling.resourceaccesssecurity.AllowingResourceAccessGate;
 import org.apache.sling.resourceaccesssecurity.ResourceAccessGate;
 
+/**
+ * Resource access gate implementing the hiding of resources.
+ */
 @Component
 @Service(value=ResourceAccessGate.class)
 public class ResourceAccessImpl
@@ -37,10 +41,9 @@ public class ResourceAccessImpl
     @Override
     public GateResult canRead(final Resource resource) {
         boolean available = true;
-        final ExecutionContextFilter.ExecutionContextInfo info = ExecutionContextFilter.getCurrentExecutionContextInfo();
+        final ClientContext info = manager.getCurrentClientContext();
         if ( info != null ) {
-            for(final String name : info.enabledFeatures) {
-                // we can't check as Feature does not have the api (TODO - we deny for now)
+            for(final String name : info.getEnabledFeatures()) {
                 available = !manager.hideResource(name, resource);
                 if ( !available) {
                     break;
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceDecoratorImpl.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceDecoratorImpl.java
index 5d2cbad..d5de62b 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceDecoratorImpl.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceDecoratorImpl.java
@@ -26,7 +26,11 @@ import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceDecorator;
 import org.apache.sling.api.resource.ResourceWrapper;
+import org.apache.sling.extensions.featureflags.ClientContext;
 
+/**
+ * Resource decorator implementing the resource type mapping
+ */
 @Component
 @Service(value=ResourceDecorator.class)
 public class ResourceDecoratorImpl implements ResourceDecorator {
@@ -36,9 +40,9 @@ public class ResourceDecoratorImpl implements ResourceDecorator {
 
     @Override
     public Resource decorate(final Resource resource) {
-        final ExecutionContextFilter.ExecutionContextInfo info = ExecutionContextFilter.getCurrentExecutionContextInfo();
+        final ClientContext info = manager.getCurrentClientContext();
         if ( info != null ) {
-            for(final String name : info.enabledFeatures) {
+            for(final String name : info.getEnabledFeatures()) {
 
                 final String resourceType = resource.getResourceType();
                 final String overwriteType = manager.getResourceType(name, resourceType);

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 11/25: Remove FeatureProvider interface, Features are OSGi services now - rename ProviderContext to ExecutionContext

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit 9f8c00a3b6de8acc667bd8ee412109be882f6ee6
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Fri Jan 10 07:35:56 2014 +0000

    Remove FeatureProvider interface, Features are OSGi services now - rename ProviderContext to ExecutionContext
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/feature-flags@1557047 13f79535-47bb-0310-9956-ffa450edef68
---
 src/main/java/org/apache/sling/featureflags/Feature.java | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/main/java/org/apache/sling/featureflags/Feature.java b/src/main/java/org/apache/sling/featureflags/Feature.java
index ca83b08..5bec8fd 100644
--- a/src/main/java/org/apache/sling/featureflags/Feature.java
+++ b/src/main/java/org/apache/sling/featureflags/Feature.java
@@ -30,6 +30,8 @@ import aQute.bnd.annotation.ConsumerType;
  *   <li>{@link ResourceHiding}</li>
  *   <li>{@link ResourceTypeMapping}</li>
  * </ul>
+ *
+ * Features are registered as OSGi services.
  */
 @ConsumerType
 public interface Feature extends Adaptable {

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 07/25: Take III, add Feature interface and support adapting to functionality interfaces

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit 8bf39037ca76fdc3a919734fa82c93d08efbca1f
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Tue Dec 31 13:12:05 2013 +0000

    Take III, add Feature interface and support adapting to functionality interfaces
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/whiteboard/feature-flags@1554505 13f79535-47bb-0310-9956-ffa450edef68
---
 .../apache/sling/featureflags/ClientContext.java   |   2 +-
 .../{ClientContext.java => Feature.java}           |  27 ++--
 .../apache/sling/featureflags/FeatureProvider.java |  28 +----
 .../org/apache/sling/featureflags/Features.java    |  14 ++-
 .../{ClientContext.java => ResourceHiding.java}    |  28 ++---
 ...{ClientContext.java => ResourceTypeMapper.java} |  28 ++---
 .../sling/featureflags/impl/ClientContextImpl.java |  57 +++++++--
 .../sling/featureflags/impl/FeatureManager.java    | 140 +++++++++++----------
 .../sling/featureflags/impl/FeaturesImpl.java      |  11 ++
 .../featureflags/impl/ResourceAccessImpl.java      |   5 +-
 .../featureflags/impl/ResourceDecoratorImpl.java   |   5 +-
 11 files changed, 195 insertions(+), 150 deletions(-)

diff --git a/src/main/java/org/apache/sling/featureflags/ClientContext.java b/src/main/java/org/apache/sling/featureflags/ClientContext.java
index 90fca71..61d5814 100644
--- a/src/main/java/org/apache/sling/featureflags/ClientContext.java
+++ b/src/main/java/org/apache/sling/featureflags/ClientContext.java
@@ -39,5 +39,5 @@ public interface ClientContext {
      * Returns a list of all enabled features
      * @return The list of features, the list might be empty.
      */
-    Collection<String> getEnabledFeatures();
+    Collection<Feature> getEnabledFeatures();
 }
diff --git a/src/main/java/org/apache/sling/featureflags/ClientContext.java b/src/main/java/org/apache/sling/featureflags/Feature.java
similarity index 62%
copy from src/main/java/org/apache/sling/featureflags/ClientContext.java
copy to src/main/java/org/apache/sling/featureflags/Feature.java
index 90fca71..9dc0f26 100644
--- a/src/main/java/org/apache/sling/featureflags/ClientContext.java
+++ b/src/main/java/org/apache/sling/featureflags/Feature.java
@@ -18,26 +18,29 @@
  */
 package org.apache.sling.featureflags;
 
-import java.util.Collection;
+import org.apache.sling.api.adapter.Adaptable;
 
-import aQute.bnd.annotation.ProviderType;
+import aQute.bnd.annotation.ConsumerType;
 
 /**
- * The client context can be used by client code to check whether
- * a specific feature is enable.
- * A client context can be created through the {@link Features} service.
+ * A feature is defined by its name.
+ * Depending on the functionality the feature implements it can
+ * be adapted to different services, like
+ * <ul>
+ *   <li>{@link ResourceHiding}</li>
+ *   <li>{@link ResourceTypeMapper}</li>
+ * </ul>
  */
-@ProviderType
-public interface ClientContext {
+@ConsumerType
+public interface Feature extends Adaptable {
 
     /**
-     * Returns <code>true</code> if the feature is enabled.
+     * The name of the feature.
      */
-    boolean isEnabled(String featureName);
+    String getName();
 
     /**
-     * Returns a list of all enabled features
-     * @return The list of features, the list might be empty.
+     * The description of the feature.
      */
-    Collection<String> getEnabledFeatures();
+    String getDescription();
 }
diff --git a/src/main/java/org/apache/sling/featureflags/FeatureProvider.java b/src/main/java/org/apache/sling/featureflags/FeatureProvider.java
index 8e0c1ed..704246e 100644
--- a/src/main/java/org/apache/sling/featureflags/FeatureProvider.java
+++ b/src/main/java/org/apache/sling/featureflags/FeatureProvider.java
@@ -18,10 +18,6 @@
  */
 package org.apache.sling.featureflags;
 
-import java.util.Map;
-
-import org.apache.sling.api.resource.Resource;
-
 import aQute.bnd.annotation.ConsumerType;
 
 /**
@@ -34,30 +30,10 @@ public interface FeatureProvider {
      * Checks whether the feature is enabled for the current execution
      * context.
      */
-    boolean isEnabled(String featureName, ProviderContext context);
+    boolean isEnabled(Feature feature, ProviderContext context);
 
     /**
      * Return the list of available features from this provider.
      */
-    String [] getFeatureNames();
-
-    /**
-     * Returns the resource type mapping for a feature.
-     * This mapping is only used if {@link #isEnabled(String, ExecutionContext)}
-     * return true for the given feature/context. The caller of this
-     * method must ensure to call {@link #isEnabled(String, ExecutionContext)}
-     * before calling this method and only call this method if
-     * {@link #isEnabled(String, ExecutionContext)} return <code>true</code>
-     */
-    Map<String, String> getResourceTypeMapping(String featureName);
-
-    /**
-     * Checks whether a resource should be hidden for a feature.
-     * This check is only executed if {@link #isEnabled(String, ExecutionContext)}
-     * return true for the given feature/context. The caller of this
-     * method must ensure to call {@link #isEnabled(String, ExecutionContext)}
-     * before calling this method and only call this method if
-     * {@link #isEnabled(String, ExecutionContext)} return <code>true</code>
-     */
-    boolean hideResource(String featureName, Resource resource);
+    Feature[] getFeatures();
 }
diff --git a/src/main/java/org/apache/sling/featureflags/Features.java b/src/main/java/org/apache/sling/featureflags/Features.java
index 25f69f3..1b054a9 100644
--- a/src/main/java/org/apache/sling/featureflags/Features.java
+++ b/src/main/java/org/apache/sling/featureflags/Features.java
@@ -32,12 +32,24 @@ import aQute.bnd.annotation.ProviderType;
 public interface Features {
 
     /**
-     * Get the list of all available features. A feature is available
+     * Get the list of all available feature names. A feature is available
      * if there is a {@link FeatureProvider}
      */
     String[] getAvailableFeatureNames();
 
     /**
+     * Get the list of all available features. A feature is available
+     * if there is a {@link FeatureProvider}
+     */
+    Feature[] getAvailableFeatures();
+
+    /**
+     * Returns the feature with the given name.
+     * @return The feature or <code>null</code>
+     */
+    Feature getFeature(String name);
+
+    /**
      * Checks whether a feature with the given name is available.
      * A feature is available if there is a {@link FeatureProvider}
      * for that feature.
diff --git a/src/main/java/org/apache/sling/featureflags/ClientContext.java b/src/main/java/org/apache/sling/featureflags/ResourceHiding.java
similarity index 53%
copy from src/main/java/org/apache/sling/featureflags/ClientContext.java
copy to src/main/java/org/apache/sling/featureflags/ResourceHiding.java
index 90fca71..7bd21ba 100644
--- a/src/main/java/org/apache/sling/featureflags/ClientContext.java
+++ b/src/main/java/org/apache/sling/featureflags/ResourceHiding.java
@@ -18,26 +18,24 @@
  */
 package org.apache.sling.featureflags;
 
-import java.util.Collection;
+import org.apache.sling.api.resource.Resource;
 
-import aQute.bnd.annotation.ProviderType;
+import aQute.bnd.annotation.ConsumerType;
 
 /**
- * The client context can be used by client code to check whether
- * a specific feature is enable.
- * A client context can be created through the {@link Features} service.
+ * A {@link Feature} which is hiding resources can be adapted to
+ * this service interface.
  */
-@ProviderType
-public interface ClientContext {
+@ConsumerType
+public interface ResourceHiding {
 
     /**
-     * Returns <code>true</code> if the feature is enabled.
+     * Checks whether a resource should be hidden for a feature.
+     * This check is only executed if {@link FeatureProvider#isEnabled(Feature, ExecutionContext)}
+     * return true for the given feature/context. The caller of this
+     * method must ensure to call {@link FeatureProvider#isEnabled(Feature, ExecutionContext)}
+     * before calling this method and only call this method if
+     * {@link FeatureProvider#isEnabled(Feature, ExecutionContext)} returned <code>true</code>
      */
-    boolean isEnabled(String featureName);
-
-    /**
-     * Returns a list of all enabled features
-     * @return The list of features, the list might be empty.
-     */
-    Collection<String> getEnabledFeatures();
+    boolean hideResource(Resource resource);
 }
diff --git a/src/main/java/org/apache/sling/featureflags/ClientContext.java b/src/main/java/org/apache/sling/featureflags/ResourceTypeMapper.java
similarity index 54%
copy from src/main/java/org/apache/sling/featureflags/ClientContext.java
copy to src/main/java/org/apache/sling/featureflags/ResourceTypeMapper.java
index 90fca71..311990e 100644
--- a/src/main/java/org/apache/sling/featureflags/ClientContext.java
+++ b/src/main/java/org/apache/sling/featureflags/ResourceTypeMapper.java
@@ -18,26 +18,24 @@
  */
 package org.apache.sling.featureflags;
 
-import java.util.Collection;
+import java.util.Map;
 
-import aQute.bnd.annotation.ProviderType;
+import aQute.bnd.annotation.ConsumerType;
 
 /**
- * The client context can be used by client code to check whether
- * a specific feature is enable.
- * A client context can be created through the {@link Features} service.
+ * A {@link Feature} which is mapping resource types can be adapted to
+ * this service interface.
  */
-@ProviderType
-public interface ClientContext {
+@ConsumerType
+public interface ResourceTypeMapper {
 
     /**
-     * Returns <code>true</code> if the feature is enabled.
+     * Returns the resource type mapping for a feature.
+     * This mapping is only executed if {@link FeatureProvider#isEnabled(Feature, ExecutionContext)}
+     * return true for the given feature/context. The caller of this
+     * method must ensure to call {@link FeatureProvider#isEnabled(Feature, ExecutionContext)}
+     * before calling this method and only call this method if
+     * {@link FeatureProvider#isEnabled(Feature, ExecutionContext)} returned <code>true</code>
      */
-    boolean isEnabled(String featureName);
-
-    /**
-     * Returns a list of all enabled features
-     * @return The list of features, the list might be empty.
-     */
-    Collection<String> getEnabledFeatures();
+    Map<String, String> getResourceTypeMapping();
 }
diff --git a/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java b/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java
index 651c947..e15b798 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java
@@ -21,10 +21,14 @@ package org.apache.sling.featureflags.impl;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 
 import org.apache.sling.featureflags.ClientContext;
+import org.apache.sling.featureflags.Feature;
 import org.apache.sling.featureflags.ProviderContext;
+import org.apache.sling.featureflags.ResourceHiding;
+import org.apache.sling.featureflags.ResourceTypeMapper;
 
 /**
  * Implementation of the client context
@@ -33,15 +37,37 @@ public class ClientContextImpl implements ClientContext {
 
     private final ProviderContext featureContext;
 
-    private final List<String> enabledFeatures = new ArrayList<String>();
+    private final List<Feature> enabledFeatures;
 
-    public ClientContextImpl(final ProviderContext featureContext) {
-        this.featureContext = featureContext;
-    }
+    private final List<ResourceHiding> hidingFeatures;
+
+    private final List<ResourceTypeMapper> mapperFeatures;
+
+    public ClientContextImpl(final ProviderContext featureContext, final List<Feature> features) {
+        Collections.sort(features, new Comparator<Feature>() {
+
+            @Override
+            public int compare(final Feature arg0, final Feature arg1) {
+                return arg0.getName().compareTo(arg1.getName());
+            }
 
-    public void addFeature(final String name) {
-        this.enabledFeatures.add(name);
-        Collections.sort(this.enabledFeatures);
+        });
+        this.enabledFeatures = Collections.unmodifiableList(features);
+        final List<ResourceHiding> hiding = new ArrayList<ResourceHiding>();
+        final List<ResourceTypeMapper> mapping = new ArrayList<ResourceTypeMapper>();
+        for(final Feature f : this.enabledFeatures) {
+            final ResourceHiding rh = f.adaptTo(ResourceHiding.class);
+            if ( rh != null ) {
+                hiding.add(rh);
+            }
+            final ResourceTypeMapper rm = f.adaptTo(ResourceTypeMapper.class);
+            if ( rm != null ) {
+                mapping.add(rm);
+            }
+        }
+        this.hidingFeatures = hiding;
+        this.mapperFeatures = mapping;
+        this.featureContext = featureContext;
     }
 
     public ProviderContext getFeatureContext() {
@@ -50,11 +76,24 @@ public class ClientContextImpl implements ClientContext {
 
     @Override
     public boolean isEnabled(final String featureName) {
-        return this.enabledFeatures.contains(featureName);
+        for(final Feature f : this.enabledFeatures) {
+            if ( featureName.equals(f.getName()) ) {
+                return true;
+            }
+        }
+        return false;
     }
 
     @Override
-    public Collection<String> getEnabledFeatures() {
+    public Collection<Feature> getEnabledFeatures() {
         return this.enabledFeatures;
     }
+
+    public Collection<ResourceHiding> getHidingFeatures() {
+        return this.hidingFeatures;
+    }
+
+    public Collection<ResourceTypeMapper> getMappingFeatures() {
+        return this.mapperFeatures;
+    }
 }
diff --git a/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java b/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
index 092e62b..63faf52 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
@@ -29,13 +29,15 @@ 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.SlingHttpServletRequest;
-import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.featureflags.ClientContext;
+import org.apache.sling.featureflags.Feature;
 import org.apache.sling.featureflags.FeatureProvider;
 import org.apache.sling.featureflags.Features;
 import org.apache.sling.featureflags.ProviderContext;
 import org.osgi.framework.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * This service implements the feature handling.
@@ -48,33 +50,32 @@ import org.osgi.framework.Constants;
            referenceInterface=FeatureProvider.class)
 public class FeatureManager implements Features {
 
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
     private final Map<String, List<FeatureProviderDescription>> providers = new HashMap<String, List<FeatureProviderDescription>>();
 
-    private Map<String, FeatureProvider> activeProviders = new HashMap<String, FeatureProvider>();
+    private Map<String, FeatureDescription> activeProviders = new HashMap<String, FeatureDescription>();
 
     /**
      * Bind a new feature provider
      */
     protected void bindFeatureProvider(final FeatureProvider provider, final Map<String, Object> props) {
-        final String[] features = provider.getFeatureNames();
+        final Feature[] features = provider.getFeatures();
         if ( features != null && features.length > 0 ) {
-            final FeatureProviderDescription info = new FeatureProviderDescription(provider, props);
             synchronized ( this.providers ) {
                 boolean changed = false;
-                for(final String n : features) {
-                    if ( n != null ) {
-                        final String name = n.trim();
-                        if ( name.length() > 0 ) {
-                            List<FeatureProviderDescription> candidates = this.providers.get(name);
-                            if ( candidates == null ) {
-                                candidates = new ArrayList<FeatureProviderDescription>();
-                                this.providers.put(name, candidates);
-                            }
-                            candidates.add(info);
-                            Collections.sort(candidates);
-                            changed = true;
-                        }
+                for(final Feature f : features) {
+                    final String name = f.getName();
+                    final FeatureProviderDescription info = new FeatureProviderDescription(provider, props, f);
+
+                    List<FeatureProviderDescription> candidates = this.providers.get(name);
+                    if ( candidates == null ) {
+                        candidates = new ArrayList<FeatureProviderDescription>();
+                        this.providers.put(name, candidates);
                     }
+                    candidates.add(info);
+                    Collections.sort(candidates);
+                    changed = true;
                 }
                 if ( changed ) {
                     this.calculateActiveProviders();
@@ -87,23 +88,20 @@ public class FeatureManager implements Features {
      * Unbind a feature provider
      */
     protected void unbindFeatureProvider(final FeatureProvider provider, final Map<String, Object> props) {
-        final String[] features = provider.getFeatureNames();
+        final Feature[] features = provider.getFeatures();
         if ( features != null && features.length > 0 ) {
-            final FeatureProviderDescription info = new FeatureProviderDescription(provider, props);
             synchronized ( this.providers ) {
                 boolean changed = false;
-                for(final String n : features) {
-                    if ( n != null ) {
-                        final String name = n.trim();
-                        if ( name.length() > 0 ) {
-                            final List<FeatureProviderDescription> candidates = this.providers.get(name);
-                            if ( candidates != null ) { // sanity check
-                                candidates.remove(info);
-                                if ( candidates.size() == 0 ) {
-                                    this.providers.remove(name);
-                                    changed = true;
-                                }
-                            }
+                for(final Feature f : features) {
+                    final String name = f.getName();
+                    final FeatureProviderDescription info = new FeatureProviderDescription(provider, props, f);
+
+                    final List<FeatureProviderDescription> candidates = this.providers.get(name);
+                    if ( candidates != null ) { // sanity check
+                        candidates.remove(info);
+                        if ( candidates.size() == 0 ) {
+                            this.providers.remove(name);
+                            changed = true;
                         }
                     }
                 }
@@ -115,9 +113,16 @@ public class FeatureManager implements Features {
     }
 
     private void calculateActiveProviders() {
-        final Map<String, FeatureProvider> activeMap = new HashMap<String, FeatureProvider>();
+        final Map<String, FeatureDescription> activeMap = new HashMap<String, FeatureDescription>();
         for(final Map.Entry<String, List<FeatureProviderDescription>> entry : this.providers.entrySet()) {
-            activeMap.put(entry.getKey(), entry.getValue().get(0).getProvider());
+            final FeatureProviderDescription desc = entry.getValue().get(0);
+            final FeatureDescription info = new FeatureDescription();
+            info.feature = desc.feature;
+            info.provider = desc.provider;
+            activeMap.put(entry.getKey(), info);
+            if ( entry.getValue().size() > 1 ) {
+                logger.warn("More than one feature provider for feature {}", entry.getKey());
+            }
         }
         this.activeProviders = activeMap;
     }
@@ -160,21 +165,40 @@ public class FeatureManager implements Features {
     }
 
     private ClientContextImpl createClientContext(final ProviderContext providerContext) {
-        final ClientContextImpl ctx = new ClientContextImpl(providerContext);
+        final List<Feature> enabledFeatures = new ArrayList<Feature>();
 
-        for(final Map.Entry<String, FeatureProvider> entry : this.activeProviders.entrySet()) {
-            final String name = entry.getKey();
-            final FeatureProvider provider = entry.getValue();
+        for(final Map.Entry<String, FeatureDescription> entry : this.activeProviders.entrySet()) {
+            final Feature f = entry.getValue().feature;
 
-            if ( provider.isEnabled(name, providerContext) ) {
-                ctx.addFeature(name);
+            if ( entry.getValue().provider.isEnabled(f, providerContext) ) {
+                enabledFeatures.add(f);
             }
         }
 
+        final ClientContextImpl ctx = new ClientContextImpl(providerContext, enabledFeatures);
         return ctx;
     }
 
     @Override
+    public Feature[] getAvailableFeatures() {
+        final List<Feature> result = new ArrayList<Feature>();
+        for(final Map.Entry<String, FeatureDescription> entry : this.activeProviders.entrySet()) {
+            final Feature f = entry.getValue().feature;
+            result.add(f);
+        }
+        return result.toArray(new Feature[result.size()]);
+    }
+
+    @Override
+    public Feature getFeature(final String name) {
+        final FeatureDescription desc = this.activeProviders.get(name);
+        if ( desc != null ) {
+            return desc.feature;
+        }
+        return null;
+    }
+
+    @Override
     public String[] getAvailableFeatureNames() {
         return this.activeProviders.keySet().toArray(new String[this.activeProviders.size()]);
     }
@@ -185,29 +209,20 @@ public class FeatureManager implements Features {
     }
 
     /**
-     * Checks whether a resource should be hidden for a feature.
-     * This check is only executed if {@link #isEnabled(String, ClientContext)}
-     * return true for the given feature/context.
-     */
-    public boolean hideResource(final String featureName, final Resource resource) {
-        final FeatureProvider prod = this.activeProviders.get(featureName);
-        if ( prod != null ) {
-            return prod.hideResource(featureName, resource);
-        }
-        return false;
-    }
-
-    /**
      * Internal class caching some provider infos like service id and ranking.
      */
     private final static class FeatureProviderDescription implements Comparable<FeatureProviderDescription> {
 
-        public FeatureProvider provider;
+        public final FeatureProvider provider;
         public final int ranking;
         public final long serviceId;
+        public final Feature feature;
 
-        public FeatureProviderDescription(final FeatureProvider provider, final Map<String, Object> props) {
+        public FeatureProviderDescription(final FeatureProvider provider,
+                final Map<String, Object> props,
+                final Feature feature) {
             this.provider = provider;
+            this.feature = feature;
             final Object sr = props.get(Constants.SERVICE_RANKING);
             if ( sr == null || !(sr instanceof Integer)) {
                 this.ranking = 0;
@@ -243,20 +258,11 @@ public class FeatureManager implements Features {
             result = prime * result + (int) (serviceId ^ (serviceId >>> 32));
             return result;
         }
-
-        public FeatureProvider getProvider() {
-            return provider;
-        }
     }
 
-    public String getResourceType(final String featureName, final String resourceType) {
-        final FeatureProvider prod = this.activeProviders.get(featureName);
-        if ( prod != null ) {
-            final Map<String, String> mapping = prod.getResourceTypeMapping(featureName);
-            if ( mapping != null ) {
-                return mapping.get(resourceType);
-            }
-        }
-        return null;
+    private final static class FeatureDescription {
+        public Feature feature;
+        public FeatureProvider provider;
+
     }
 }
diff --git a/src/main/java/org/apache/sling/featureflags/impl/FeaturesImpl.java b/src/main/java/org/apache/sling/featureflags/impl/FeaturesImpl.java
index 1c5ce53..e0e836e 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/FeaturesImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/FeaturesImpl.java
@@ -24,6 +24,7 @@ import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.featureflags.ClientContext;
+import org.apache.sling.featureflags.Feature;
 import org.apache.sling.featureflags.Features;
 
 /**
@@ -47,6 +48,16 @@ public class FeaturesImpl implements Features {
     }
 
     @Override
+    public Feature[] getAvailableFeatures() {
+        return this.manager.getAvailableFeatures();
+    }
+
+    @Override
+    public Feature getFeature(final String name) {
+        return this.manager.getFeature(name);
+    }
+
+    @Override
     public ClientContext getCurrentClientContext() {
         return this.manager.getCurrentClientContext();
     }
diff --git a/src/main/java/org/apache/sling/featureflags/impl/ResourceAccessImpl.java b/src/main/java/org/apache/sling/featureflags/impl/ResourceAccessImpl.java
index 3164e7b..2dd05f1 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/ResourceAccessImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/ResourceAccessImpl.java
@@ -23,6 +23,7 @@ import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.featureflags.ClientContext;
+import org.apache.sling.featureflags.ResourceHiding;
 import org.apache.sling.resourceaccesssecurity.AllowingResourceAccessGate;
 import org.apache.sling.resourceaccesssecurity.ResourceAccessGate;
 
@@ -43,8 +44,8 @@ public class ResourceAccessImpl
         boolean available = true;
         final ClientContext info = manager.getCurrentClientContext();
         if ( info != null ) {
-            for(final String name : info.getEnabledFeatures()) {
-                available = !manager.hideResource(name, resource);
+            for(final ResourceHiding f : ((ClientContextImpl)info).getHidingFeatures() ) {
+                available = !f.hideResource(resource);
                 if ( !available) {
                     break;
                 }
diff --git a/src/main/java/org/apache/sling/featureflags/impl/ResourceDecoratorImpl.java b/src/main/java/org/apache/sling/featureflags/impl/ResourceDecoratorImpl.java
index 12e76ea..2118d43 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/ResourceDecoratorImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/ResourceDecoratorImpl.java
@@ -27,6 +27,7 @@ import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceDecorator;
 import org.apache.sling.api.resource.ResourceWrapper;
 import org.apache.sling.featureflags.ClientContext;
+import org.apache.sling.featureflags.ResourceTypeMapper;
 
 /**
  * Resource decorator implementing the resource type mapping
@@ -42,10 +43,10 @@ public class ResourceDecoratorImpl implements ResourceDecorator {
     public Resource decorate(final Resource resource) {
         final ClientContext info = manager.getCurrentClientContext();
         if ( info != null ) {
-            for(final String name : info.getEnabledFeatures()) {
+            for(final ResourceTypeMapper f : ((ClientContextImpl)info).getMappingFeatures() ) {
 
                 final String resourceType = resource.getResourceType();
-                final String overwriteType = manager.getResourceType(name, resourceType);
+                final String overwriteType = f.getResourceTypeMapping().get(resourceType);
                 if ( overwriteType != null ) {
                     return new ResourceWrapper(resource) {
 

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 22/25: SLING-3484 - Remove FeatureAuthenticationInfoPostProcessor and FeatureConstants, unneeded

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit ff85fb860f6e531d67d7e6c3f1018342bc0816ce
Author: Bertrand Delacretaz <bd...@apache.org>
AuthorDate: Thu Mar 27 10:47:18 2014 +0000

    SLING-3484 - Remove FeatureAuthenticationInfoPostProcessor and FeatureConstants, unneeded
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/feature-flags@1582249 13f79535-47bb-0310-9956-ffa450edef68
---
 .../sling/featureflags/FeatureConstants.java       | 31 -------------
 .../FeatureAuthenticationInfoPostProcessor.java    | 52 ----------------------
 2 files changed, 83 deletions(-)

diff --git a/src/main/java/org/apache/sling/featureflags/FeatureConstants.java b/src/main/java/org/apache/sling/featureflags/FeatureConstants.java
deleted file mode 100644
index 47b1f8b..0000000
--- a/src/main/java/org/apache/sling/featureflags/FeatureConstants.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.
- */
-package org.apache.sling.featureflags;
-
-
-public abstract class FeatureConstants {
-
-    /**
-     * The name of the resource resolver attribute which is set if the
-     * feature flag support should be enabled in the resource resolver.
-     * The value of this property should be of type Boolean. The default
-     * is <code>false</code>
-     */
-    public static final String RESOLVER_ATTR_FEATURES_ENABLED = "sling.resourceresolver.feature";
-}
diff --git a/src/main/java/org/apache/sling/featureflags/impl/FeatureAuthenticationInfoPostProcessor.java b/src/main/java/org/apache/sling/featureflags/impl/FeatureAuthenticationInfoPostProcessor.java
deleted file mode 100644
index ab2f30c..0000000
--- a/src/main/java/org/apache/sling/featureflags/impl/FeatureAuthenticationInfoPostProcessor.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.
- */
-package org.apache.sling.featureflags.impl;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.felix.scr.annotations.Component;
-import org.apache.felix.scr.annotations.Service;
-import org.apache.sling.api.resource.LoginException;
-import org.apache.sling.auth.core.spi.AuthenticationInfo;
-import org.apache.sling.auth.core.spi.AuthenticationInfoPostProcessor;
-import org.apache.sling.featureflags.FeatureConstants;
-
-/**
- * This authentication info post processor enables the feature flag support
- * in the resource resolver for GET and HEAD requests.
- */
-@Component
-@Service(value=AuthenticationInfoPostProcessor.class)
-public class FeatureAuthenticationInfoPostProcessor implements AuthenticationInfoPostProcessor {
-
-    /**
-     * @see org.apache.sling.auth.core.spi.AuthenticationInfoPostProcessor#postProcess(org.apache.sling.auth.core.spi.AuthenticationInfo, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
-     */
-    @Override
-    public void postProcess(final AuthenticationInfo info,
-            final HttpServletRequest request,
-            final HttpServletResponse response)
-    throws LoginException {
-        if ( "GET".equals(request.getMethod()) || "HEAD".equals(request.getMethod()) ) {
-            info.put(FeatureConstants.RESOLVER_ATTR_FEATURES_ENABLED, Boolean.TRUE);
-        }
-    }
-
-}

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 06/25: Remove "extensions" from package name

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit 085cc03941434736835cf17d5d8dd9eaf8152dad
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Tue Dec 31 10:56:41 2013 +0000

    Remove "extensions" from package name
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/whiteboard/feature-flags@1554399 13f79535-47bb-0310-9956-ffa450edef68
---
 .../sling/{extensions => }/featureflags/ClientContext.java     |  2 +-
 .../sling/{extensions => }/featureflags/FeatureProvider.java   |  2 +-
 .../apache/sling/{extensions => }/featureflags/Features.java   |  2 +-
 .../sling/{extensions => }/featureflags/ProviderContext.java   |  2 +-
 .../{extensions => }/featureflags/impl/ClientContextImpl.java  |  6 +++---
 .../featureflags/impl/CurrentClientContextFilter.java          |  2 +-
 .../{extensions => }/featureflags/impl/FeatureManager.java     | 10 +++++-----
 .../sling/{extensions => }/featureflags/impl/FeaturesImpl.java |  6 +++---
 .../featureflags/impl/ProviderContextImpl.java                 |  4 ++--
 .../{extensions => }/featureflags/impl/ResourceAccessImpl.java |  4 ++--
 .../featureflags/impl/ResourceDecoratorImpl.java               |  4 ++--
 .../sling/{extensions => }/featureflags/package-info.java      |  2 +-
 12 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/src/main/java/org/apache/sling/extensions/featureflags/ClientContext.java b/src/main/java/org/apache/sling/featureflags/ClientContext.java
similarity index 96%
rename from src/main/java/org/apache/sling/extensions/featureflags/ClientContext.java
rename to src/main/java/org/apache/sling/featureflags/ClientContext.java
index d44387b..90fca71 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/ClientContext.java
+++ b/src/main/java/org/apache/sling/featureflags/ClientContext.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.extensions.featureflags;
+package org.apache.sling.featureflags;
 
 import java.util.Collection;
 
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/FeatureProvider.java b/src/main/java/org/apache/sling/featureflags/FeatureProvider.java
similarity index 97%
rename from src/main/java/org/apache/sling/extensions/featureflags/FeatureProvider.java
rename to src/main/java/org/apache/sling/featureflags/FeatureProvider.java
index 2c8c7c6..8e0c1ed 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/FeatureProvider.java
+++ b/src/main/java/org/apache/sling/featureflags/FeatureProvider.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.extensions.featureflags;
+package org.apache.sling.featureflags;
 
 import java.util.Map;
 
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/Features.java b/src/main/java/org/apache/sling/featureflags/Features.java
similarity index 97%
rename from src/main/java/org/apache/sling/extensions/featureflags/Features.java
rename to src/main/java/org/apache/sling/featureflags/Features.java
index 28af24d..25f69f3 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/Features.java
+++ b/src/main/java/org/apache/sling/featureflags/Features.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.extensions.featureflags;
+package org.apache.sling.featureflags;
 
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.ResourceResolver;
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/ProviderContext.java b/src/main/java/org/apache/sling/featureflags/ProviderContext.java
similarity index 96%
rename from src/main/java/org/apache/sling/extensions/featureflags/ProviderContext.java
rename to src/main/java/org/apache/sling/featureflags/ProviderContext.java
index 8af8a8c..08b400b 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/ProviderContext.java
+++ b/src/main/java/org/apache/sling/featureflags/ProviderContext.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.extensions.featureflags;
+package org.apache.sling.featureflags;
 
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.ResourceResolver;
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/ClientContextImpl.java b/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java
similarity index 90%
rename from src/main/java/org/apache/sling/extensions/featureflags/impl/ClientContextImpl.java
rename to src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java
index b4228e3..651c947 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/ClientContextImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java
@@ -16,15 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.extensions.featureflags.impl;
+package org.apache.sling.featureflags.impl;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 
-import org.apache.sling.extensions.featureflags.ClientContext;
-import org.apache.sling.extensions.featureflags.ProviderContext;
+import org.apache.sling.featureflags.ClientContext;
+import org.apache.sling.featureflags.ProviderContext;
 
 /**
  * Implementation of the client context
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/CurrentClientContextFilter.java b/src/main/java/org/apache/sling/featureflags/impl/CurrentClientContextFilter.java
similarity index 97%
rename from src/main/java/org/apache/sling/extensions/featureflags/impl/CurrentClientContextFilter.java
rename to src/main/java/org/apache/sling/featureflags/impl/CurrentClientContextFilter.java
index 349538f..9399666 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/CurrentClientContextFilter.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/CurrentClientContextFilter.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.extensions.featureflags.impl;
+package org.apache.sling.featureflags.impl;
 
 import java.io.IOException;
 
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureManager.java b/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
similarity index 97%
rename from src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureManager.java
rename to src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
index 38fac8a..092e62b 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureManager.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.extensions.featureflags.impl;
+package org.apache.sling.featureflags.impl;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -31,10 +31,10 @@ import org.apache.felix.scr.annotations.ReferencePolicy;
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.extensions.featureflags.ClientContext;
-import org.apache.sling.extensions.featureflags.FeatureProvider;
-import org.apache.sling.extensions.featureflags.Features;
-import org.apache.sling.extensions.featureflags.ProviderContext;
+import org.apache.sling.featureflags.ClientContext;
+import org.apache.sling.featureflags.FeatureProvider;
+import org.apache.sling.featureflags.Features;
+import org.apache.sling.featureflags.ProviderContext;
 import org.osgi.framework.Constants;
 
 /**
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeaturesImpl.java b/src/main/java/org/apache/sling/featureflags/impl/FeaturesImpl.java
similarity index 91%
rename from src/main/java/org/apache/sling/extensions/featureflags/impl/FeaturesImpl.java
rename to src/main/java/org/apache/sling/featureflags/impl/FeaturesImpl.java
index 75ef89f..1c5ce53 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeaturesImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/FeaturesImpl.java
@@ -16,15 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.extensions.featureflags.impl;
+package org.apache.sling.featureflags.impl;
 
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.extensions.featureflags.ClientContext;
-import org.apache.sling.extensions.featureflags.Features;
+import org.apache.sling.featureflags.ClientContext;
+import org.apache.sling.featureflags.Features;
 
 /**
  * This is a wrapper around the internal feature manager.
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/ProviderContextImpl.java b/src/main/java/org/apache/sling/featureflags/impl/ProviderContextImpl.java
similarity index 93%
rename from src/main/java/org/apache/sling/extensions/featureflags/impl/ProviderContextImpl.java
rename to src/main/java/org/apache/sling/featureflags/impl/ProviderContextImpl.java
index 3c66929..e162b16 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/ProviderContextImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/ProviderContextImpl.java
@@ -16,11 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.extensions.featureflags.impl;
+package org.apache.sling.featureflags.impl;
 
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.extensions.featureflags.ProviderContext;
+import org.apache.sling.featureflags.ProviderContext;
 
 /**
  * Implementation of the provider context.
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceAccessImpl.java b/src/main/java/org/apache/sling/featureflags/impl/ResourceAccessImpl.java
similarity index 94%
rename from src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceAccessImpl.java
rename to src/main/java/org/apache/sling/featureflags/impl/ResourceAccessImpl.java
index befc1c1..3164e7b 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceAccessImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/ResourceAccessImpl.java
@@ -16,13 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.extensions.featureflags.impl;
+package org.apache.sling.featureflags.impl;
 
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.resource.Resource;
-import org.apache.sling.extensions.featureflags.ClientContext;
+import org.apache.sling.featureflags.ClientContext;
 import org.apache.sling.resourceaccesssecurity.AllowingResourceAccessGate;
 import org.apache.sling.resourceaccesssecurity.ResourceAccessGate;
 
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceDecoratorImpl.java b/src/main/java/org/apache/sling/featureflags/impl/ResourceDecoratorImpl.java
similarity index 95%
rename from src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceDecoratorImpl.java
rename to src/main/java/org/apache/sling/featureflags/impl/ResourceDecoratorImpl.java
index d5de62b..12e76ea 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceDecoratorImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/ResourceDecoratorImpl.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.extensions.featureflags.impl;
+package org.apache.sling.featureflags.impl;
 
 import javax.servlet.http.HttpServletRequest;
 
@@ -26,7 +26,7 @@ import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceDecorator;
 import org.apache.sling.api.resource.ResourceWrapper;
-import org.apache.sling.extensions.featureflags.ClientContext;
+import org.apache.sling.featureflags.ClientContext;
 
 /**
  * Resource decorator implementing the resource type mapping
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/package-info.java b/src/main/java/org/apache/sling/featureflags/package-info.java
similarity index 95%
rename from src/main/java/org/apache/sling/extensions/featureflags/package-info.java
rename to src/main/java/org/apache/sling/featureflags/package-info.java
index f1cdd16..90264d0 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/package-info.java
+++ b/src/main/java/org/apache/sling/featureflags/package-info.java
@@ -24,7 +24,7 @@
  * @version 1.0
  */
 @Version("1.0")
-package org.apache.sling.extensions.featureflags;
+package org.apache.sling.featureflags;
 
 import aQute.bnd.annotation.Version;
 

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 08/25: Moving feature flags into trunk

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit 3e0d5943af004a0c9e057908dfe5f8d9adcf15c6
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Fri Jan 3 08:24:07 2014 +0000

    Moving feature flags into trunk
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/feature-flags@1555027 13f79535-47bb-0310-9956-ffa450edef68

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 13/25: Use released Sling API

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit 04166051d45216789e8f7e55211e3ec833bc59da
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Fri Jan 24 22:40:42 2014 +0000

    Use released Sling API
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/feature-flags@1561218 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 6a40896..7f62fee 100644
--- a/pom.xml
+++ b/pom.xml
@@ -43,7 +43,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.api</artifactId>
-            <version>2.4.3-SNAPSHOT</version>
+            <version>2.5.0</version>
             <scope>provided</scope>
         </dependency>
         <dependency>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 09/25: Take III, add Feature interface and support adapting to functionality interfaces

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit 35ebee9a827ec6cd78f2122ce9ce4b3c3031cde5
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Fri Jan 3 08:52:41 2014 +0000

    Take III, add Feature interface and support adapting to functionality interfaces
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/feature-flags@1555034 13f79535-47bb-0310-9956-ffa450edef68
---
 .../org/apache/sling/featureflags/Feature.java     |  2 +-
 ...rceTypeMapper.java => ResourceTypeMapping.java} |  2 +-
 .../sling/featureflags/impl/ClientContextImpl.java | 24 ++++++-----------
 .../sling/featureflags/impl/FeatureManager.java    |  5 ++--
 .../featureflags/impl/ResourceDecoratorImpl.java   | 30 ++++++++++------------
 5 files changed, 26 insertions(+), 37 deletions(-)

diff --git a/src/main/java/org/apache/sling/featureflags/Feature.java b/src/main/java/org/apache/sling/featureflags/Feature.java
index 9dc0f26..cedbb61 100644
--- a/src/main/java/org/apache/sling/featureflags/Feature.java
+++ b/src/main/java/org/apache/sling/featureflags/Feature.java
@@ -28,7 +28,7 @@ import aQute.bnd.annotation.ConsumerType;
  * be adapted to different services, like
  * <ul>
  *   <li>{@link ResourceHiding}</li>
- *   <li>{@link ResourceTypeMapper}</li>
+ *   <li>{@link ResourceTypeMapping}</li>
  * </ul>
  */
 @ConsumerType
diff --git a/src/main/java/org/apache/sling/featureflags/ResourceTypeMapper.java b/src/main/java/org/apache/sling/featureflags/ResourceTypeMapping.java
similarity index 97%
rename from src/main/java/org/apache/sling/featureflags/ResourceTypeMapper.java
rename to src/main/java/org/apache/sling/featureflags/ResourceTypeMapping.java
index 311990e..7f6f3c6 100644
--- a/src/main/java/org/apache/sling/featureflags/ResourceTypeMapper.java
+++ b/src/main/java/org/apache/sling/featureflags/ResourceTypeMapping.java
@@ -27,7 +27,7 @@ import aQute.bnd.annotation.ConsumerType;
  * this service interface.
  */
 @ConsumerType
-public interface ResourceTypeMapper {
+public interface ResourceTypeMapping {
 
     /**
      * Returns the resource type mapping for a feature.
diff --git a/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java b/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java
index e15b798..03b0506 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java
@@ -21,14 +21,15 @@ package org.apache.sling.featureflags.impl;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.sling.featureflags.ClientContext;
 import org.apache.sling.featureflags.Feature;
 import org.apache.sling.featureflags.ProviderContext;
 import org.apache.sling.featureflags.ResourceHiding;
-import org.apache.sling.featureflags.ResourceTypeMapper;
+import org.apache.sling.featureflags.ResourceTypeMapping;
 
 /**
  * Implementation of the client context
@@ -41,32 +42,23 @@ public class ClientContextImpl implements ClientContext {
 
     private final List<ResourceHiding> hidingFeatures;
 
-    private final List<ResourceTypeMapper> mapperFeatures;
+    private final Map<String, String> mapperFeatures = new HashMap<String, String>();
 
     public ClientContextImpl(final ProviderContext featureContext, final List<Feature> features) {
-        Collections.sort(features, new Comparator<Feature>() {
-
-            @Override
-            public int compare(final Feature arg0, final Feature arg1) {
-                return arg0.getName().compareTo(arg1.getName());
-            }
-
-        });
         this.enabledFeatures = Collections.unmodifiableList(features);
         final List<ResourceHiding> hiding = new ArrayList<ResourceHiding>();
-        final List<ResourceTypeMapper> mapping = new ArrayList<ResourceTypeMapper>();
         for(final Feature f : this.enabledFeatures) {
             final ResourceHiding rh = f.adaptTo(ResourceHiding.class);
             if ( rh != null ) {
                 hiding.add(rh);
             }
-            final ResourceTypeMapper rm = f.adaptTo(ResourceTypeMapper.class);
+            final ResourceTypeMapping rm = f.adaptTo(ResourceTypeMapping.class);
             if ( rm != null ) {
-                mapping.add(rm);
+                final Map<String, String> mapping = rm.getResourceTypeMapping();
+                mapperFeatures.putAll(mapping);
             }
         }
         this.hidingFeatures = hiding;
-        this.mapperFeatures = mapping;
         this.featureContext = featureContext;
     }
 
@@ -93,7 +85,7 @@ public class ClientContextImpl implements ClientContext {
         return this.hidingFeatures;
     }
 
-    public Collection<ResourceTypeMapper> getMappingFeatures() {
+    public Map<String, String> getResourceTypeMapping() {
         return this.mapperFeatures;
     }
 }
diff --git a/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java b/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
index 63faf52..c9813e3 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
@@ -23,6 +23,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.TreeMap;
 
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Reference;
@@ -54,7 +55,7 @@ public class FeatureManager implements Features {
 
     private final Map<String, List<FeatureProviderDescription>> providers = new HashMap<String, List<FeatureProviderDescription>>();
 
-    private Map<String, FeatureDescription> activeProviders = new HashMap<String, FeatureDescription>();
+    private Map<String, FeatureDescription> activeProviders = new TreeMap<String, FeatureDescription>();
 
     /**
      * Bind a new feature provider
@@ -113,7 +114,7 @@ public class FeatureManager implements Features {
     }
 
     private void calculateActiveProviders() {
-        final Map<String, FeatureDescription> activeMap = new HashMap<String, FeatureDescription>();
+        final Map<String, FeatureDescription> activeMap = new TreeMap<String, FeatureDescription>();
         for(final Map.Entry<String, List<FeatureProviderDescription>> entry : this.providers.entrySet()) {
             final FeatureProviderDescription desc = entry.getValue().get(0);
             final FeatureDescription info = new FeatureDescription();
diff --git a/src/main/java/org/apache/sling/featureflags/impl/ResourceDecoratorImpl.java b/src/main/java/org/apache/sling/featureflags/impl/ResourceDecoratorImpl.java
index 2118d43..e2f818d 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/ResourceDecoratorImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/ResourceDecoratorImpl.java
@@ -27,7 +27,6 @@ import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceDecorator;
 import org.apache.sling.api.resource.ResourceWrapper;
 import org.apache.sling.featureflags.ClientContext;
-import org.apache.sling.featureflags.ResourceTypeMapper;
 
 /**
  * Resource decorator implementing the resource type mapping
@@ -43,24 +42,21 @@ public class ResourceDecoratorImpl implements ResourceDecorator {
     public Resource decorate(final Resource resource) {
         final ClientContext info = manager.getCurrentClientContext();
         if ( info != null ) {
-            for(final ResourceTypeMapper f : ((ClientContextImpl)info).getMappingFeatures() ) {
+            final String resourceType = resource.getResourceType();
+            final String overwriteType = ((ClientContextImpl)info).getResourceTypeMapping().get(resourceType);
+            if ( overwriteType != null ) {
+                return new ResourceWrapper(resource) {
 
-                final String resourceType = resource.getResourceType();
-                final String overwriteType = f.getResourceTypeMapping().get(resourceType);
-                if ( overwriteType != null ) {
-                    return new ResourceWrapper(resource) {
+                    @Override
+                    public String getResourceType() {
+                        return overwriteType;
+                    }
 
-                        @Override
-                        public String getResourceType() {
-                            return overwriteType;
-                        }
-
-                        @Override
-                        public String getResourceSuperType() {
-                            return resourceType;
-                        }
-                    };
-                }
+                    @Override
+                    public String getResourceSuperType() {
+                        return resourceType;
+                    }
+                };
             }
         }
         return resource;

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 04/25: Take II for the feature flags, separate into different contexts to avoid duplicate evaluation

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit fae60b1d27140aee92ece67806293b0e743d13d9
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Thu Dec 19 04:48:45 2013 +0000

    Take II for the feature flags, separate into different contexts to avoid duplicate evaluation
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/whiteboard/feature-flags@1552226 13f79535-47bb-0310-9956-ffa450edef68
---
 .../extensions/featureflags/impl/FeatureManager.java | 20 ++++++++++----------
 ...tureContextImpl.java => ProviderContextImpl.java} |  9 ++++++---
 2 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureManager.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureManager.java
index 2fbf286..4d42d0a 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureManager.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureManager.java
@@ -32,9 +32,9 @@ import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.extensions.featureflags.ClientContext;
-import org.apache.sling.extensions.featureflags.ProviderContext;
 import org.apache.sling.extensions.featureflags.FeatureProvider;
 import org.apache.sling.extensions.featureflags.Features;
+import org.apache.sling.extensions.featureflags.ProviderContext;
 import org.osgi.framework.Constants;
 
 /**
@@ -130,8 +130,8 @@ public class FeatureManager implements Features {
     }
 
     public void setCurrentClientContext(final SlingHttpServletRequest request) {
-        final ProviderContext featureContext = new FeatureContextImpl(request);
-        final ClientContextImpl ctx = this.createClientContext(featureContext);
+        final ProviderContext providerContext = new ProviderContextImpl(request);
+        final ClientContextImpl ctx = this.createClientContext(providerContext);
         perThreadClientContext.set(ctx);
     }
 
@@ -144,8 +144,8 @@ public class FeatureManager implements Features {
         if ( resolver == null ) {
             throw new IllegalArgumentException("Resolver must not be null.");
         }
-        final ProviderContext featureContext = new FeatureContextImpl(resolver);
-        final ClientContext ctx = this.createClientContext(featureContext);
+        final ProviderContext providerContext = new ProviderContextImpl(resolver);
+        final ClientContext ctx = this.createClientContext(providerContext);
         return ctx;
     }
 
@@ -154,19 +154,19 @@ public class FeatureManager implements Features {
         if ( request == null ) {
             throw new IllegalArgumentException("Request must not be null.");
         }
-        final ProviderContext featureContext = new FeatureContextImpl(request);
-        final ClientContext ctx = this.createClientContext(featureContext);
+        final ProviderContext providerContext = new ProviderContextImpl(request);
+        final ClientContext ctx = this.createClientContext(providerContext);
         return ctx;
     }
 
-    private ClientContextImpl createClientContext(final ProviderContext featureContext) {
-        final ClientContextImpl ctx = new ClientContextImpl(featureContext);
+    private ClientContextImpl createClientContext(final ProviderContext providerContext) {
+        final ClientContextImpl ctx = new ClientContextImpl(providerContext);
 
         for(final Map.Entry<String, FeatureProvider> entry : this.activeProviders.entrySet()) {
             final String name = entry.getKey();
             final FeatureProvider provider = entry.getValue();
 
-            if ( provider.isEnabled(name, featureContext) ) {
+            if ( provider.isEnabled(name, providerContext) ) {
                 ctx.addFeature(name);
             }
         }
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureContextImpl.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/ProviderContextImpl.java
similarity index 85%
rename from src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureContextImpl.java
rename to src/main/java/org/apache/sling/extensions/featureflags/impl/ProviderContextImpl.java
index e31dc15..3c66929 100644
--- a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureContextImpl.java
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/ProviderContextImpl.java
@@ -22,18 +22,21 @@ import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.extensions.featureflags.ProviderContext;
 
-public class FeatureContextImpl implements ProviderContext {
+/**
+ * Implementation of the provider context.
+ */
+public class ProviderContextImpl implements ProviderContext {
 
     private final ResourceResolver resourceResolver;
 
     private final SlingHttpServletRequest request;
 
-    public FeatureContextImpl(final ResourceResolver resourceResolver) {
+    public ProviderContextImpl(final ResourceResolver resourceResolver) {
         this.request = null;
         this.resourceResolver = resourceResolver;
     }
 
-    public FeatureContextImpl(final SlingHttpServletRequest request) {
+    public ProviderContextImpl(final SlingHttpServletRequest request) {
         this.request = request;
         this.resourceResolver = request.getResourceResolver();
     }

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 10/25: Remove FeatureProvider interface, Features are OSGi services now - rename ProviderContext to ExecutionContext

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit 7a1c95e2990b7102354a0521959217b115349f27
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Fri Jan 10 07:29:24 2014 +0000

    Remove FeatureProvider interface, Features are OSGi services now - rename ProviderContext to ExecutionContext
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/feature-flags@1557045 13f79535-47bb-0310-9956-ffa450edef68
---
 ...{ProviderContext.java => ExecutionContext.java} |   5 +-
 .../org/apache/sling/featureflags/Feature.java     |   6 +
 .../apache/sling/featureflags/FeatureProvider.java |  39 -----
 .../org/apache/sling/featureflags/Features.java    |  11 +-
 .../apache/sling/featureflags/ResourceHiding.java  |   6 +-
 .../sling/featureflags/ResourceTypeMapping.java    |   6 +-
 .../sling/featureflags/impl/ClientContextImpl.java |   8 +-
 ...rContextImpl.java => ExecutionContextImpl.java} |   8 +-
 .../sling/featureflags/impl/FeatureManager.java    | 159 ++++++++++-----------
 9 files changed, 102 insertions(+), 146 deletions(-)

diff --git a/src/main/java/org/apache/sling/featureflags/ProviderContext.java b/src/main/java/org/apache/sling/featureflags/ExecutionContext.java
similarity index 92%
rename from src/main/java/org/apache/sling/featureflags/ProviderContext.java
rename to src/main/java/org/apache/sling/featureflags/ExecutionContext.java
index 08b400b..d01bd67 100644
--- a/src/main/java/org/apache/sling/featureflags/ProviderContext.java
+++ b/src/main/java/org/apache/sling/featureflags/ExecutionContext.java
@@ -25,11 +25,10 @@ import aQute.bnd.annotation.ProviderType;
 
 /**
  * The provider context contains all information that is passed to a
- * {@link FeatureProvider} in order to check whether a feature
- * is enabled.
+ * {@link Feature} in order to check whether a feature is enabled.
  */
 @ProviderType
-public interface ProviderContext {
+public interface ExecutionContext {
 
     /**
      * Return the associated request if available
diff --git a/src/main/java/org/apache/sling/featureflags/Feature.java b/src/main/java/org/apache/sling/featureflags/Feature.java
index cedbb61..ca83b08 100644
--- a/src/main/java/org/apache/sling/featureflags/Feature.java
+++ b/src/main/java/org/apache/sling/featureflags/Feature.java
@@ -35,6 +35,12 @@ import aQute.bnd.annotation.ConsumerType;
 public interface Feature extends Adaptable {
 
     /**
+     * Checks whether the feature is enabled for the current execution
+     * context.
+     */
+    boolean isEnabled(ExecutionContext context);
+
+    /**
      * The name of the feature.
      */
     String getName();
diff --git a/src/main/java/org/apache/sling/featureflags/FeatureProvider.java b/src/main/java/org/apache/sling/featureflags/FeatureProvider.java
deleted file mode 100644
index 704246e..0000000
--- a/src/main/java/org/apache/sling/featureflags/FeatureProvider.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- */
-package org.apache.sling.featureflags;
-
-import aQute.bnd.annotation.ConsumerType;
-
-/**
- * A feature provider activates one more features.
- */
-@ConsumerType
-public interface FeatureProvider {
-
-    /**
-     * Checks whether the feature is enabled for the current execution
-     * context.
-     */
-    boolean isEnabled(Feature feature, ProviderContext context);
-
-    /**
-     * Return the list of available features from this provider.
-     */
-    Feature[] getFeatures();
-}
diff --git a/src/main/java/org/apache/sling/featureflags/Features.java b/src/main/java/org/apache/sling/featureflags/Features.java
index 1b054a9..8b6a810 100644
--- a/src/main/java/org/apache/sling/featureflags/Features.java
+++ b/src/main/java/org/apache/sling/featureflags/Features.java
@@ -33,13 +33,13 @@ public interface Features {
 
     /**
      * Get the list of all available feature names. A feature is available
-     * if there is a {@link FeatureProvider}
+     * if there is a registered {@link Feature} service.
      */
     String[] getAvailableFeatureNames();
 
     /**
      * Get the list of all available features. A feature is available
-     * if there is a {@link FeatureProvider}
+     * if there is a registered {@link Feature} service.
      */
     Feature[] getAvailableFeatures();
 
@@ -51,13 +51,14 @@ public interface Features {
 
     /**
      * Checks whether a feature with the given name is available.
-     * A feature is available if there is a {@link FeatureProvider}
-     * for that feature.
+     * A feature is available if there is a registered {@link Feature} service.
      */
     boolean isAvailable(String featureName);
 
     /**
-     * Returns the current client context, if available
+     * Returns the current client context.
+     * This method always returns a client context object
+     * @return A client context.
      */
     ClientContext getCurrentClientContext();
 
diff --git a/src/main/java/org/apache/sling/featureflags/ResourceHiding.java b/src/main/java/org/apache/sling/featureflags/ResourceHiding.java
index 7bd21ba..d19fab6 100644
--- a/src/main/java/org/apache/sling/featureflags/ResourceHiding.java
+++ b/src/main/java/org/apache/sling/featureflags/ResourceHiding.java
@@ -31,11 +31,11 @@ public interface ResourceHiding {
 
     /**
      * Checks whether a resource should be hidden for a feature.
-     * This check is only executed if {@link FeatureProvider#isEnabled(Feature, ExecutionContext)}
+     * This check is only executed if {@link Feature#isEnabled(ExecutionContext)}
      * return true for the given feature/context. The caller of this
-     * method must ensure to call {@link FeatureProvider#isEnabled(Feature, ExecutionContext)}
+     * method must ensure to call {@link Feature#isEnabled(ExecutionContext)}
      * before calling this method and only call this method if
-     * {@link FeatureProvider#isEnabled(Feature, ExecutionContext)} returned <code>true</code>
+     * {@link Feature#isEnabled(ExecutionContext)} returned <code>true</code>
      */
     boolean hideResource(Resource resource);
 }
diff --git a/src/main/java/org/apache/sling/featureflags/ResourceTypeMapping.java b/src/main/java/org/apache/sling/featureflags/ResourceTypeMapping.java
index 7f6f3c6..a9ca5f4 100644
--- a/src/main/java/org/apache/sling/featureflags/ResourceTypeMapping.java
+++ b/src/main/java/org/apache/sling/featureflags/ResourceTypeMapping.java
@@ -31,11 +31,11 @@ public interface ResourceTypeMapping {
 
     /**
      * Returns the resource type mapping for a feature.
-     * This mapping is only executed if {@link FeatureProvider#isEnabled(Feature, ExecutionContext)}
+     * This mapping is only executed if {@link Feature#isEnabled(ExecutionContext)}
      * return true for the given feature/context. The caller of this
-     * method must ensure to call {@link FeatureProvider#isEnabled(Feature, ExecutionContext)}
+     * method must ensure to call {@link Feature#isEnabled(ExecutionContext)}
      * before calling this method and only call this method if
-     * {@link FeatureProvider#isEnabled(Feature, ExecutionContext)} returned <code>true</code>
+     * {@link Feature#isEnabled(ExecutionContext)} returned <code>true</code>
      */
     Map<String, String> getResourceTypeMapping();
 }
diff --git a/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java b/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java
index 03b0506..b71ebe4 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java
@@ -27,7 +27,7 @@ import java.util.Map;
 
 import org.apache.sling.featureflags.ClientContext;
 import org.apache.sling.featureflags.Feature;
-import org.apache.sling.featureflags.ProviderContext;
+import org.apache.sling.featureflags.ExecutionContext;
 import org.apache.sling.featureflags.ResourceHiding;
 import org.apache.sling.featureflags.ResourceTypeMapping;
 
@@ -36,7 +36,7 @@ import org.apache.sling.featureflags.ResourceTypeMapping;
  */
 public class ClientContextImpl implements ClientContext {
 
-    private final ProviderContext featureContext;
+    private final ExecutionContext featureContext;
 
     private final List<Feature> enabledFeatures;
 
@@ -44,7 +44,7 @@ public class ClientContextImpl implements ClientContext {
 
     private final Map<String, String> mapperFeatures = new HashMap<String, String>();
 
-    public ClientContextImpl(final ProviderContext featureContext, final List<Feature> features) {
+    public ClientContextImpl(final ExecutionContext featureContext, final List<Feature> features) {
         this.enabledFeatures = Collections.unmodifiableList(features);
         final List<ResourceHiding> hiding = new ArrayList<ResourceHiding>();
         for(final Feature f : this.enabledFeatures) {
@@ -62,7 +62,7 @@ public class ClientContextImpl implements ClientContext {
         this.featureContext = featureContext;
     }
 
-    public ProviderContext getFeatureContext() {
+    public ExecutionContext getFeatureContext() {
         return this.featureContext;
     }
 
diff --git a/src/main/java/org/apache/sling/featureflags/impl/ProviderContextImpl.java b/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java
similarity index 85%
rename from src/main/java/org/apache/sling/featureflags/impl/ProviderContextImpl.java
rename to src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java
index e162b16..555575f 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/ProviderContextImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java
@@ -20,23 +20,23 @@ package org.apache.sling.featureflags.impl;
 
 import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.featureflags.ProviderContext;
+import org.apache.sling.featureflags.ExecutionContext;
 
 /**
  * Implementation of the provider context.
  */
-public class ProviderContextImpl implements ProviderContext {
+public class ExecutionContextImpl implements ExecutionContext {
 
     private final ResourceResolver resourceResolver;
 
     private final SlingHttpServletRequest request;
 
-    public ProviderContextImpl(final ResourceResolver resourceResolver) {
+    public ExecutionContextImpl(final ResourceResolver resourceResolver) {
         this.request = null;
         this.resourceResolver = resourceResolver;
     }
 
-    public ProviderContextImpl(final SlingHttpServletRequest request) {
+    public ExecutionContextImpl(final SlingHttpServletRequest request) {
         this.request = request;
         this.resourceResolver = request.getResourceResolver();
     }
diff --git a/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java b/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
index c9813e3..fd601f6 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
@@ -19,6 +19,7 @@
 package org.apache.sling.featureflags.impl;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -33,110 +34,107 @@ import org.apache.sling.api.SlingHttpServletRequest;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.featureflags.ClientContext;
 import org.apache.sling.featureflags.Feature;
-import org.apache.sling.featureflags.FeatureProvider;
 import org.apache.sling.featureflags.Features;
-import org.apache.sling.featureflags.ProviderContext;
+import org.apache.sling.featureflags.ExecutionContext;
 import org.osgi.framework.Constants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
  * This service implements the feature handling.
- * It keeps track of all {@link FeatureProvider} services.
+ * It keeps track of all {@link Feature} services.
  */
 @Component
-@Reference(name="featureProvider",
+@Reference(name="feature",
            cardinality=ReferenceCardinality.OPTIONAL_MULTIPLE,
            policy=ReferencePolicy.DYNAMIC,
-           referenceInterface=FeatureProvider.class)
+           referenceInterface=Feature.class)
 public class FeatureManager implements Features {
 
     private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
-    private final Map<String, List<FeatureProviderDescription>> providers = new HashMap<String, List<FeatureProviderDescription>>();
+    private final Map<String, List<FeatureDescription>> allFeatures = new HashMap<String, List<FeatureDescription>>();
 
-    private Map<String, FeatureDescription> activeProviders = new TreeMap<String, FeatureDescription>();
+    private Map<String, FeatureDescription> activeFeatures = new TreeMap<String, FeatureDescription>();
 
     /**
-     * Bind a new feature provider
+     * Bind a new feature
      */
-    protected void bindFeatureProvider(final FeatureProvider provider, final Map<String, Object> props) {
-        final Feature[] features = provider.getFeatures();
-        if ( features != null && features.length > 0 ) {
-            synchronized ( this.providers ) {
-                boolean changed = false;
-                for(final Feature f : features) {
-                    final String name = f.getName();
-                    final FeatureProviderDescription info = new FeatureProviderDescription(provider, props, f);
-
-                    List<FeatureProviderDescription> candidates = this.providers.get(name);
-                    if ( candidates == null ) {
-                        candidates = new ArrayList<FeatureProviderDescription>();
-                        this.providers.put(name, candidates);
-                    }
-                    candidates.add(info);
-                    Collections.sort(candidates);
-                    changed = true;
-                }
-                if ( changed ) {
-                    this.calculateActiveProviders();
-                }
+    protected void bindFeature(final Feature f, final Map<String, Object> props) {
+        synchronized ( this.allFeatures ) {
+            final String name = f.getName();
+            final FeatureDescription info = new FeatureDescription(f, props);
+
+            List<FeatureDescription> candidates = this.allFeatures.get(name);
+            if ( candidates == null ) {
+                candidates = new ArrayList<FeatureDescription>();
+                this.allFeatures.put(name, candidates);
             }
+            candidates.add(info);
+            Collections.sort(candidates);
+
+            this.calculateActiveProviders();
         }
     }
 
     /**
-     * Unbind a feature provider
+     * Unbind a feature
      */
-    protected void unbindFeatureProvider(final FeatureProvider provider, final Map<String, Object> props) {
-        final Feature[] features = provider.getFeatures();
-        if ( features != null && features.length > 0 ) {
-            synchronized ( this.providers ) {
-                boolean changed = false;
-                for(final Feature f : features) {
-                    final String name = f.getName();
-                    final FeatureProviderDescription info = new FeatureProviderDescription(provider, props, f);
-
-                    final List<FeatureProviderDescription> candidates = this.providers.get(name);
-                    if ( candidates != null ) { // sanity check
-                        candidates.remove(info);
-                        if ( candidates.size() == 0 ) {
-                            this.providers.remove(name);
-                            changed = true;
-                        }
-                    }
-                }
-                if ( changed ) {
-                    this.calculateActiveProviders();
+    protected void unbindFeature(final Feature f, final Map<String, Object> props) {
+        synchronized ( this.allFeatures ) {
+            final String name = f.getName();
+            final FeatureDescription info = new FeatureDescription(f, props);
+
+            final List<FeatureDescription> candidates = this.allFeatures.get(name);
+            if ( candidates != null ) { // sanity check
+                candidates.remove(info);
+                if ( candidates.size() == 0 ) {
+                    this.allFeatures.remove(name);
                 }
             }
+            this.calculateActiveProviders();
         }
     }
 
     private void calculateActiveProviders() {
         final Map<String, FeatureDescription> activeMap = new TreeMap<String, FeatureDescription>();
-        for(final Map.Entry<String, List<FeatureProviderDescription>> entry : this.providers.entrySet()) {
-            final FeatureProviderDescription desc = entry.getValue().get(0);
-            final FeatureDescription info = new FeatureDescription();
-            info.feature = desc.feature;
-            info.provider = desc.provider;
-            activeMap.put(entry.getKey(), info);
+        for(final Map.Entry<String, List<FeatureDescription>> entry : this.allFeatures.entrySet()) {
+            final FeatureDescription desc = entry.getValue().get(0);
+
+            activeMap.put(entry.getKey(), desc);
             if ( entry.getValue().size() > 1 ) {
-                logger.warn("More than one feature provider for feature {}", entry.getKey());
+                logger.warn("More than one feature service for feature {}", entry.getKey());
             }
         }
-        this.activeProviders = activeMap;
+        this.activeFeatures = activeMap;
     }
 
     private final ThreadLocal<ClientContextImpl> perThreadClientContext = new ThreadLocal<ClientContextImpl>();
 
+    private final ClientContext defaultClientContext = new ClientContext() {
+
+        @Override
+        public boolean isEnabled(final String featureName) {
+            return false;
+        }
+
+        @Override
+        public Collection<Feature> getEnabledFeatures() {
+            return Collections.emptyList();
+        }
+    };
+
     @Override
     public ClientContext getCurrentClientContext() {
-        return perThreadClientContext.get();
+        ClientContext result = perThreadClientContext.get();
+        if ( result == null ) {
+            result = defaultClientContext;
+        }
+        return result;
     }
 
     public void setCurrentClientContext(final SlingHttpServletRequest request) {
-        final ProviderContext providerContext = new ProviderContextImpl(request);
+        final ExecutionContext providerContext = new ExecutionContextImpl(request);
         final ClientContextImpl ctx = this.createClientContext(providerContext);
         perThreadClientContext.set(ctx);
     }
@@ -150,7 +148,7 @@ public class FeatureManager implements Features {
         if ( resolver == null ) {
             throw new IllegalArgumentException("Resolver must not be null.");
         }
-        final ProviderContext providerContext = new ProviderContextImpl(resolver);
+        final ExecutionContext providerContext = new ExecutionContextImpl(resolver);
         final ClientContext ctx = this.createClientContext(providerContext);
         return ctx;
     }
@@ -160,18 +158,18 @@ public class FeatureManager implements Features {
         if ( request == null ) {
             throw new IllegalArgumentException("Request must not be null.");
         }
-        final ProviderContext providerContext = new ProviderContextImpl(request);
+        final ExecutionContext providerContext = new ExecutionContextImpl(request);
         final ClientContext ctx = this.createClientContext(providerContext);
         return ctx;
     }
 
-    private ClientContextImpl createClientContext(final ProviderContext providerContext) {
+    private ClientContextImpl createClientContext(final ExecutionContext providerContext) {
         final List<Feature> enabledFeatures = new ArrayList<Feature>();
 
-        for(final Map.Entry<String, FeatureDescription> entry : this.activeProviders.entrySet()) {
+        for(final Map.Entry<String, FeatureDescription> entry : this.activeFeatures.entrySet()) {
             final Feature f = entry.getValue().feature;
 
-            if ( entry.getValue().provider.isEnabled(f, providerContext) ) {
+            if ( entry.getValue().feature.isEnabled(providerContext) ) {
                 enabledFeatures.add(f);
             }
         }
@@ -183,7 +181,7 @@ public class FeatureManager implements Features {
     @Override
     public Feature[] getAvailableFeatures() {
         final List<Feature> result = new ArrayList<Feature>();
-        for(final Map.Entry<String, FeatureDescription> entry : this.activeProviders.entrySet()) {
+        for(final Map.Entry<String, FeatureDescription> entry : this.activeFeatures.entrySet()) {
             final Feature f = entry.getValue().feature;
             result.add(f);
         }
@@ -192,7 +190,7 @@ public class FeatureManager implements Features {
 
     @Override
     public Feature getFeature(final String name) {
-        final FeatureDescription desc = this.activeProviders.get(name);
+        final FeatureDescription desc = this.activeFeatures.get(name);
         if ( desc != null ) {
             return desc.feature;
         }
@@ -201,28 +199,25 @@ public class FeatureManager implements Features {
 
     @Override
     public String[] getAvailableFeatureNames() {
-        return this.activeProviders.keySet().toArray(new String[this.activeProviders.size()]);
+        return this.activeFeatures.keySet().toArray(new String[this.activeFeatures.size()]);
     }
 
     @Override
     public boolean isAvailable(final String featureName) {
-        return this.activeProviders.containsKey(featureName);
+        return this.activeFeatures.containsKey(featureName);
     }
 
     /**
-     * Internal class caching some provider infos like service id and ranking.
+     * Internal class caching some feature meta data like service id and ranking.
      */
-    private final static class FeatureProviderDescription implements Comparable<FeatureProviderDescription> {
+    private final static class FeatureDescription implements Comparable<FeatureDescription> {
 
-        public final FeatureProvider provider;
         public final int ranking;
         public final long serviceId;
         public final Feature feature;
 
-        public FeatureProviderDescription(final FeatureProvider provider,
-                final Map<String, Object> props,
-                final Feature feature) {
-            this.provider = provider;
+        public FeatureDescription(final Feature feature,
+                final Map<String, Object> props) {
             this.feature = feature;
             final Object sr = props.get(Constants.SERVICE_RANKING);
             if ( sr == null || !(sr instanceof Integer)) {
@@ -234,7 +229,7 @@ public class FeatureManager implements Features {
         }
 
         @Override
-        public int compareTo(final FeatureProviderDescription o) {
+        public int compareTo(final FeatureDescription o) {
             if ( this.ranking < o.ranking ) {
                 return 1;
             } else if (this.ranking > o.ranking ) {
@@ -246,8 +241,8 @@ public class FeatureManager implements Features {
 
         @Override
         public boolean equals(final Object obj) {
-            if ( obj instanceof FeatureProviderDescription ) {
-                return ((FeatureProviderDescription)obj).serviceId == this.serviceId;
+            if ( obj instanceof FeatureDescription ) {
+                return ((FeatureDescription)obj).serviceId == this.serviceId;
             }
             return false;
         }
@@ -260,10 +255,4 @@ public class FeatureManager implements Features {
             return result;
         }
     }
-
-    private final static class FeatureDescription {
-        public Feature feature;
-        public FeatureProvider provider;
-
-    }
 }

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 01/25: New Feature Flags prototype

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit b660cb40e1ad5fea7b3b8cbd2683b673f2b45815
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Thu Dec 19 01:21:55 2013 +0000

    New Feature Flags prototype
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/whiteboard/feature-flags@1552202 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                            |  70 ++++++++
 .../extensions/featureflags/ExecutionContext.java  |  56 ++++++
 .../sling/extensions/featureflags/Feature.java     |  54 ++++++
 .../extensions/featureflags/FeatureProvider.java   |  57 ++++++
 .../featureflags/impl/ExecutionContextFilter.java  | 100 +++++++++++
 .../extensions/featureflags/impl/FeatureImpl.java  | 196 +++++++++++++++++++++
 .../featureflags/impl/ResourceAccessImpl.java      |  51 ++++++
 .../extensions/featureflags/package-info.java      |  30 ++++
 8 files changed, 614 insertions(+)

diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..6a40896
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>18</version>
+    </parent>
+    
+    <groupId>org.apache.sling</groupId>
+    <artifactId>org.apache.sling.featureflags</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+    <name>Apache Sling Feature Flags</name>
+    
+    <properties>
+        <sling.java.version>6</sling.java.version>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-scr-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+            </plugin>
+        </plugins>
+    </build>
+    
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.api</artifactId>
+            <version>2.4.3-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.resourceaccesssecurity</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.commons.osgi</artifactId>
+            <version>2.2.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>servlet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/ExecutionContext.java b/src/main/java/org/apache/sling/extensions/featureflags/ExecutionContext.java
new file mode 100644
index 0000000..8e00dfd
--- /dev/null
+++ b/src/main/java/org/apache/sling/extensions/featureflags/ExecutionContext.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+package org.apache.sling.extensions.featureflags;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.ResourceResolver;
+
+public class ExecutionContext {
+
+    private final ResourceResolver resourceResolver;
+
+    private final SlingHttpServletRequest request;
+
+    public static ExecutionContext fromRequest(final SlingHttpServletRequest request) {
+        return new ExecutionContext(request);
+    }
+
+    public static ExecutionContext fromResourceResolver(final ResourceResolver resourceResolver) {
+        return new ExecutionContext(resourceResolver);
+    }
+
+    private ExecutionContext(final ResourceResolver resourceResolver) {
+        this.request = null;
+        this.resourceResolver = resourceResolver;
+    }
+
+
+    private ExecutionContext(final SlingHttpServletRequest request) {
+        this.request = request;
+        this.resourceResolver = request.getResourceResolver();
+    }
+
+    public SlingHttpServletRequest getRequest() {
+        return this.request;
+    }
+
+    public ResourceResolver getResourceResolver() {
+        return this.resourceResolver;
+    }
+}
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/Feature.java b/src/main/java/org/apache/sling/extensions/featureflags/Feature.java
new file mode 100644
index 0000000..ed901c5
--- /dev/null
+++ b/src/main/java/org/apache/sling/extensions/featureflags/Feature.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+package org.apache.sling.extensions.featureflags;
+
+import aQute.bnd.annotation.ProviderType;
+
+/**
+ * The feature service is the central gateway for feature handling.
+ * It can be used to query the available features and to
+ * check whether a feature is enabled for the current execution
+ * context.
+ */
+@ProviderType
+public interface Feature {
+
+
+    /**
+     * Checks whether the feature is enabled for the given
+     * execution context.
+     *
+     * The actual check is delegated to the {@link FeatureProvider}
+     * providing the feature.
+     */
+    boolean isEnabled(String featureName, ExecutionContext context);
+
+    /** Get the list of active feature flags */
+    String[] getFeatureNames();
+
+    /**
+     * Checks whether a feature with the given name is available.
+     * A feature is available if there is a {@link FeatureProvider}
+     * for that feature.
+     * @param featureName
+     * @return
+     */
+    boolean isAvailable(String featureName);
+
+}
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/FeatureProvider.java b/src/main/java/org/apache/sling/extensions/featureflags/FeatureProvider.java
new file mode 100644
index 0000000..66264b9
--- /dev/null
+++ b/src/main/java/org/apache/sling/extensions/featureflags/FeatureProvider.java
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+package org.apache.sling.extensions.featureflags;
+
+import java.util.Map;
+
+import org.apache.sling.api.resource.Resource;
+
+import aQute.bnd.annotation.ConsumerType;
+
+/**
+ * A feature provider activates one more features.
+ */
+@ConsumerType
+public interface FeatureProvider {
+
+    /**
+     * Checks whether the feature is enabled for the current execution
+     * context.
+     */
+    boolean isEnabled(String featureName, ExecutionContext context);
+
+    /**
+     * Return the list of available features from this provider.
+     */
+    String [] getFeatureNames();
+
+    /**
+     * Returns the resource type mapping for a feature.
+     * This mapping is only used if {@link #isEnabled(String, ExecutionContext)}
+     * return true for the given feature/context.
+     */
+    Map<String, String> getResourceTypeMapping(String featureName);
+
+    /**
+     * Checks whether a resource should be hidden for a feature.
+     * This check is only executed if {@link #isEnabled(String, ExecutionContext)}
+     * return true for the given feature/context.
+     */
+    boolean hideResource(String featureName, Resource resource);
+}
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/ExecutionContextFilter.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/ExecutionContextFilter.java
new file mode 100644
index 0000000..7ee7b85
--- /dev/null
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/ExecutionContextFilter.java
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+package org.apache.sling.extensions.featureflags.impl;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.extensions.featureflags.ExecutionContext;
+import org.apache.sling.extensions.featureflags.Feature;
+
+@Component
+@Service(value=Filter.class)
+@Property(name="pattern", value="/.*")
+public class ExecutionContextFilter implements Filter {
+
+    private static ThreadLocal<ExecutionContextInfo> EXECUTION_CONTEXT;
+
+    @Reference
+    private Feature feature;
+
+    public static ExecutionContextInfo getCurrentExecutionContextInfo() {
+        final ThreadLocal<ExecutionContextInfo> local = EXECUTION_CONTEXT;
+        if ( local != null ) {
+            return local.get();
+        }
+        return null;
+    }
+
+    @Override
+    public void destroy() {
+        EXECUTION_CONTEXT = null;
+    }
+
+    @Override
+    public void doFilter(final ServletRequest req, final ServletResponse res,
+            final FilterChain chain)
+    throws IOException, ServletException {
+        final ThreadLocal<ExecutionContextInfo> local = EXECUTION_CONTEXT;
+        if ( local != null && req instanceof SlingHttpServletRequest ) {
+            local.set(new ExecutionContextInfo((SlingHttpServletRequest)req, feature));
+        }
+        try {
+            chain.doFilter(req, res);
+        } finally {
+            if ( local != null && req instanceof SlingHttpServletRequest ) {
+                local.set(null);
+            }
+        }
+    }
+
+    @Override
+    public void init(final FilterConfig config) throws ServletException {
+        EXECUTION_CONTEXT = new ThreadLocal<ExecutionContextInfo>();
+    }
+
+    public final class ExecutionContextInfo {
+
+        public final ExecutionContext context;
+        public final Set<String> enabledFeatures = new HashSet<String>();
+
+        public ExecutionContextInfo(final SlingHttpServletRequest req,
+                final Feature feature) {
+            this.context = ExecutionContext.fromRequest(req);
+            for(final String name : feature.getFeatureNames()) {
+                if ( feature.isEnabled(name, context) ) {
+                    enabledFeatures.add(name);
+                }
+            }
+        }
+    }
+}
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureImpl.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureImpl.java
new file mode 100644
index 0000000..65abe86
--- /dev/null
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/FeatureImpl.java
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+package org.apache.sling.extensions.featureflags.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.ReferencePolicy;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.extensions.featureflags.ExecutionContext;
+import org.apache.sling.extensions.featureflags.Feature;
+import org.apache.sling.extensions.featureflags.FeatureProvider;
+import org.osgi.framework.Constants;
+
+/**
+ * This service implements the feature handling.
+ * It keeps track of all {@link FeatureProvider} services.
+ */
+@Component
+@Service(value=Feature.class)
+@Reference(name="featureProvider",
+           cardinality=ReferenceCardinality.OPTIONAL_MULTIPLE,
+           policy=ReferencePolicy.DYNAMIC,
+           referenceInterface=FeatureProvider.class)
+public class FeatureImpl implements Feature {
+
+    private final Map<String, List<FeatureProviderDescription>> providers = new HashMap<String, List<FeatureProviderDescription>>();
+
+    private Map<String, FeatureProviderDescription> activeProviders = new HashMap<String, FeatureProviderDescription>();
+
+    /**
+     * Bind a new feature provider
+     */
+    protected void bindFeatureProvider(final FeatureProvider provider, final Map<String, Object> props) {
+        final String[] features = provider.getFeatureNames();
+        if ( features != null && features.length > 0 ) {
+            final FeatureProviderDescription info = new FeatureProviderDescription(provider, props);
+            synchronized ( this.providers ) {
+                boolean changed = false;
+                for(final String n : features) {
+                    if ( n != null ) {
+                        final String name = n.trim();
+                        if ( name.length() > 0 ) {
+                            List<FeatureProviderDescription> candidates = this.providers.get(name);
+                            if ( candidates == null ) {
+                                candidates = new ArrayList<FeatureProviderDescription>();
+                                this.providers.put(name, candidates);
+                            }
+                            candidates.add(info);
+                            Collections.sort(candidates);
+                            changed = true;
+                        }
+                    }
+                }
+                if ( changed ) {
+                    this.calculateActiveProviders();
+                }
+            }
+        }
+    }
+
+    /**
+     * Unbind a feature provider
+     */
+    protected void unbindFeatureProvider(final FeatureProvider provider, final Map<String, Object> props) {
+        final String[] features = provider.getFeatureNames();
+        if ( features != null && features.length > 0 ) {
+            final FeatureProviderDescription info = new FeatureProviderDescription(provider, props);
+            synchronized ( this.providers ) {
+                boolean changed = false;
+                for(final String n : features) {
+                    if ( n != null ) {
+                        final String name = n.trim();
+                        if ( name.length() > 0 ) {
+                            final List<FeatureProviderDescription> candidates = this.providers.get(name);
+                            if ( candidates != null ) { // sanity check
+                                candidates.remove(info);
+                                if ( candidates.size() == 0 ) {
+                                    this.providers.remove(name);
+                                    changed = true;
+                                }
+                            }
+                        }
+                    }
+                }
+                if ( changed ) {
+                    this.calculateActiveProviders();
+                }
+            }
+        }
+    }
+
+    private void calculateActiveProviders() {
+        final Map<String, FeatureProviderDescription> activeMap = new HashMap<String, FeatureImpl.FeatureProviderDescription>();
+        for(final Map.Entry<String, List<FeatureProviderDescription>> entry : this.providers.entrySet()) {
+            activeMap.put(entry.getKey(), entry.getValue().get(0));
+        }
+        this.activeProviders = activeMap;
+    }
+
+    @Override
+    public boolean isEnabled(final String featureName, final ExecutionContext context) {
+        boolean result = false;
+        final FeatureProviderDescription desc = this.activeProviders.get(featureName);
+        if ( desc != null ) {
+            final FeatureProvider prod = desc.getProvider();
+            result = prod.isEnabled(featureName, context);
+        }
+        return result;
+    }
+
+    @Override
+    public String[] getFeatureNames() {
+        return this.activeProviders.keySet().toArray(new String[this.activeProviders.size()]);
+    }
+
+    @Override
+    public boolean isAvailable(final String featureName) {
+        return this.activeProviders.containsKey(featureName);
+    }
+
+
+    /**
+     * Internal class caching some provider infos like service id and ranking.
+     */
+    private final static class FeatureProviderDescription implements Comparable<FeatureProviderDescription> {
+
+        public FeatureProvider provider;
+        public final int ranking;
+        public final long serviceId;
+
+        public FeatureProviderDescription(final FeatureProvider provider, final Map<String, Object> props) {
+            this.provider = provider;
+            final Object sr = props.get(Constants.SERVICE_RANKING);
+            if ( sr == null || !(sr instanceof Integer)) {
+                this.ranking = 0;
+            } else {
+                this.ranking = (Integer)sr;
+            }
+            this.serviceId = (Long)props.get(Constants.SERVICE_ID);
+        }
+
+        @Override
+        public int compareTo(final FeatureProviderDescription o) {
+            if ( this.ranking < o.ranking ) {
+                return 1;
+            } else if (this.ranking > o.ranking ) {
+                return -1;
+            }
+            // If ranks are equal, then sort by service id in descending order.
+            return (this.serviceId < o.serviceId) ? -1 : 1;
+        }
+
+        @Override
+        public boolean equals(final Object obj) {
+            if ( obj instanceof FeatureProviderDescription ) {
+                return ((FeatureProviderDescription)obj).serviceId == this.serviceId;
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + (int) (serviceId ^ (serviceId >>> 32));
+            return result;
+        }
+
+        public FeatureProvider getProvider() {
+            return provider;
+        }
+    }
+}
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceAccessImpl.java b/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceAccessImpl.java
new file mode 100644
index 0000000..a3bed50
--- /dev/null
+++ b/src/main/java/org/apache/sling/extensions/featureflags/impl/ResourceAccessImpl.java
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+package org.apache.sling.extensions.featureflags.impl;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.extensions.featureflags.Feature;
+import org.apache.sling.resourceaccesssecurity.AllowingResourceAccessGate;
+import org.apache.sling.resourceaccesssecurity.ResourceAccessGate;
+
+@Component
+@Service(value=ResourceAccessGate.class)
+public class ResourceAccessImpl
+    extends AllowingResourceAccessGate
+    implements ResourceAccessGate {
+
+    @Reference
+    private Feature feature;
+
+    @Override
+    public GateResult canRead(final Resource resource) {
+        boolean available = true;
+        final ExecutionContextFilter.ExecutionContextInfo info = ExecutionContextFilter.getCurrentExecutionContextInfo();
+        if ( info != null ) {
+            for(final String name : info.enabledFeatures) {
+                // we can't check as Feature does not have the api (TODO - we deny for now)
+                available = false;
+                break;
+            }
+        }
+        return (available ? GateResult.DONTCARE : GateResult.DENIED);
+    }
+}
diff --git a/src/main/java/org/apache/sling/extensions/featureflags/package-info.java b/src/main/java/org/apache/sling/extensions/featureflags/package-info.java
new file mode 100644
index 0000000..f1cdd16
--- /dev/null
+++ b/src/main/java/org/apache/sling/extensions/featureflags/package-info.java
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+/**
+ * Provides a service to interface which may be implemented by applications
+ * to get notified on cluster topology changes.
+ *
+ * @version 1.0
+ */
+@Version("1.0")
+package org.apache.sling.extensions.featureflags;
+
+import aQute.bnd.annotation.Version;
+

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 17/25: SLING-3346 Feature flag not respected

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit a43e7096f9710da3dcafdb4d5faa605447664db1
Author: Felix Meschberger <fm...@apache.org>
AuthorDate: Wed Jan 29 11:32:46 2014 +0000

    SLING-3346 Feature flag not respected
    
    - Turns out we need both filter registration because initial
       resource resolution takes place before any Sling filter is
       called
    - An issue was unconvered where negative feature checks
       had no effect
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/feature-flags@1562416 13f79535-47bb-0310-9956-ffa450edef68
---
 .../java/org/apache/sling/featureflags/impl/FeatureManager.java  | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java b/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
index 61b5641..fd87123 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
@@ -101,10 +101,17 @@ public class FeatureManager {
         services.add(bundleContext.registerService(Filter.class.getName(), new CurrentClientContextFilter(this),
             new Hashtable<String, Object>() {
                 {
-                    put("sling.filter.scope", "REQUEST");
+                    put("pattern", "/.*");
                     put("service.ranking", Integer.MIN_VALUE);
                 }
             }));
+        services.add(bundleContext.registerService(Filter.class.getName(), new CurrentClientContextFilter(this),
+            new Hashtable<String, Object>() {
+            {
+                put("sling.filter.scope", "REQUEST");
+                put("service.ranking", Integer.MIN_VALUE);
+            }
+        }));
         this.services = services;
     }
 

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 20/25: SLING-3353 Move feature flags from contrib to bundles

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit 646abb7df3d3469ca0a7b0cca0175b74756736bf
Author: Felix Meschberger <fm...@apache.org>
AuthorDate: Thu Jan 30 09:48:41 2014 +0000

    SLING-3353 Move feature flags from contrib to bundles
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/feature-flags@1562757 13f79535-47bb-0310-9956-ffa450edef68

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 16/25: Fix some typos

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit d7c990335f5420959ad89ac65a8249c6a4c1a04a
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Tue Jan 28 09:13:40 2014 +0000

    Fix some typos
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/feature-flags@1562012 13f79535-47bb-0310-9956-ffa450edef68
---
 src/main/java/org/apache/sling/featureflags/ClientContext.java    | 2 +-
 src/main/java/org/apache/sling/featureflags/ExecutionContext.java | 2 +-
 src/main/java/org/apache/sling/featureflags/package-info.java     | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/main/java/org/apache/sling/featureflags/ClientContext.java b/src/main/java/org/apache/sling/featureflags/ClientContext.java
index 137e6ff..33a392c 100644
--- a/src/main/java/org/apache/sling/featureflags/ClientContext.java
+++ b/src/main/java/org/apache/sling/featureflags/ClientContext.java
@@ -28,7 +28,7 @@ import aQute.bnd.annotation.ProviderType;
  * <p>
  * Prepared {@code ClientContext} instances are available through the
  * {@link Features} service. Consumers of this interface are not expected to
- * implent it.
+ * implement it.
  */
 @ProviderType
 public interface ClientContext {
diff --git a/src/main/java/org/apache/sling/featureflags/ExecutionContext.java b/src/main/java/org/apache/sling/featureflags/ExecutionContext.java
index 14d684d..1e91088 100644
--- a/src/main/java/org/apache/sling/featureflags/ExecutionContext.java
+++ b/src/main/java/org/apache/sling/featureflags/ExecutionContext.java
@@ -37,7 +37,7 @@ import aQute.bnd.annotation.ProviderType;
  * 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
- * behaviour.
+ * behavior.
  */
 @ProviderType
 public interface ExecutionContext {
diff --git a/src/main/java/org/apache/sling/featureflags/package-info.java b/src/main/java/org/apache/sling/featureflags/package-info.java
index f1fb45b..41b243d 100644
--- a/src/main/java/org/apache/sling/featureflags/package-info.java
+++ b/src/main/java/org/apache/sling/featureflags/package-info.java
@@ -47,7 +47,7 @@
  *  </tr>
  *  <tr>
  *      <td>{@code description}</td>
- *      <td>Description for the feature. The intent is to descibe the behaviour
+ *      <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>
  *  </tr>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-featureflags] 19/25: SLING-3350 Simplify API and implementation:

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.featureflags-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-featureflags.git

commit 7d315bae21cfaf139688360fbb1a400c964c0274
Author: Felix Meschberger <fm...@apache.org>
AuthorDate: Thu Jan 30 08:00:45 2014 +0000

    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)
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/feature-flags@1562712 13f79535-47bb-0310-9956-ffa450edef68
---
 .../apache/sling/featureflags/ClientContext.java   |  53 -----
 .../sling/featureflags/ExecutionContext.java       |  15 +-
 .../org/apache/sling/featureflags/Feature.java     |  41 ++--
 .../org/apache/sling/featureflags/Features.java    |  84 ++------
 .../sling/featureflags/impl/ClientContextImpl.java |  74 -------
 .../impl/CurrentClientContextFilter.java           |  64 ------
 .../featureflags/impl/ExecutionContextImpl.java    |  45 ++--
 .../sling/featureflags/impl/FeatureManager.java    | 233 ++++++++++-----------
 .../impl/FeatureResourceDecorator.java             |  57 -----
 .../featureflags/impl/FeatureWebConsolePlugin.java |  74 -------
 .../sling/featureflags/impl/FeaturesImpl.java      |  73 -------
 .../apache/sling/featureflags/package-info.java    |   8 +-
 12 files changed, 184 insertions(+), 637 deletions(-)

diff --git a/src/main/java/org/apache/sling/featureflags/ClientContext.java b/src/main/java/org/apache/sling/featureflags/ClientContext.java
deleted file mode 100644
index 33a392c..0000000
--- a/src/main/java/org/apache/sling/featureflags/ClientContext.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.
- */
-package org.apache.sling.featureflags;
-
-import java.util.Collection;
-
-import aQute.bnd.annotation.ProviderType;
-
-/**
- * The client context can be used by client code to check whether a specific
- * feature is enable.
- * <p>
- * Prepared {@code ClientContext} instances are available through the
- * {@link Features} service. Consumers of this interface are not expected to
- * implement it.
- */
-@ProviderType
-public interface ClientContext {
-
-    /**
-     * Returns {@code true} if the named feature is enabled.
-     *
-     * @param featureName The name of the feature.
-     * @return {@code true} if the named feature is enabled. {@code false} is
-     *         returned if the named feature is not enabled, is not known or the
-     *         {@code featureName} parameter is {@code null} or an empty String.
-     */
-    boolean isEnabled(String featureName);
-
-    /**
-     * Returns a possibly empty collection of enabled {@link Feature} instances.
-     *
-     * @return The collection of enabled {@link Feature} instances. This
-     *         collection may be empty and is not modifiable.
-     */
-    Collection<Feature> getEnabledFeatures();
-}
diff --git a/src/main/java/org/apache/sling/featureflags/ExecutionContext.java b/src/main/java/org/apache/sling/featureflags/ExecutionContext.java
index 1e91088..321a092 100644
--- a/src/main/java/org/apache/sling/featureflags/ExecutionContext.java
+++ b/src/main/java/org/apache/sling/featureflags/ExecutionContext.java
@@ -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();
 }
diff --git a/src/main/java/org/apache/sling/featureflags/Feature.java b/src/main/java/org/apache/sling/featureflags/Feature.java
index 3984df5..1d835b9 100644
--- a/src/main/java/org/apache/sling/featureflags/Feature.java
+++ b/src/main/java/org/apache/sling/featureflags/Feature.java
@@ -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);
 }
diff --git a/src/main/java/org/apache/sling/featureflags/Features.java b/src/main/java/org/apache/sling/featureflags/Features.java
index eb5faac..a1d2a69 100644
--- a/src/main/java/org/apache/sling/featureflags/Features.java
+++ b/src/main/java/org/apache/sling/featureflags/Features.java
@@ -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);
 }
diff --git a/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java b/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java
deleted file mode 100644
index dc02b25..0000000
--- a/src/main/java/org/apache/sling/featureflags/impl/ClientContextImpl.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.
- */
-package org.apache.sling.featureflags.impl;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.sling.api.resource.ResourceDecorator;
-import org.apache.sling.featureflags.ClientContext;
-import org.apache.sling.featureflags.Feature;
-import org.apache.sling.featureflags.ExecutionContext;
-
-/**
- * Implementation of the client context
- */
-public class ClientContextImpl implements ClientContext {
-
-    private final ExecutionContext featureContext;
-
-    private final Map<String, Feature> enabledFeatures;
-
-    private final List<ResourceDecorator> resourceDecorators;
-
-    public ClientContextImpl(final ExecutionContext featureContext, final Map<String, Feature> features) {
-        ArrayList<ResourceDecorator> resourceDecorators = new ArrayList<ResourceDecorator>(features.size());
-        for (final Feature f : features.values()) {
-            if (f instanceof ResourceDecorator) {
-                resourceDecorators.add((ResourceDecorator) f);
-            }
-        }
-        resourceDecorators.trimToSize();
-
-        this.featureContext = featureContext;
-        this.enabledFeatures = Collections.unmodifiableMap(features);
-        this.resourceDecorators = Collections.unmodifiableList(resourceDecorators);
-    }
-
-    public ExecutionContext getFeatureContext() {
-        return this.featureContext;
-    }
-
-    @Override
-    public boolean isEnabled(final String featureName) {
-        return this.enabledFeatures.get(featureName) != null;
-    }
-
-    @Override
-    public Collection<Feature> getEnabledFeatures() {
-        return this.enabledFeatures.values();
-    }
-
-    public List<ResourceDecorator> getResourceDecorators() {
-        return this.resourceDecorators;
-    }
-}
diff --git a/src/main/java/org/apache/sling/featureflags/impl/CurrentClientContextFilter.java b/src/main/java/org/apache/sling/featureflags/impl/CurrentClientContextFilter.java
deleted file mode 100644
index da6287f..0000000
--- a/src/main/java/org/apache/sling/featureflags/impl/CurrentClientContextFilter.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.
- */
-package org.apache.sling.featureflags.impl;
-
-import java.io.IOException;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import org.apache.sling.featureflags.ClientContext;
-
-/**
- * This general servlet filter sets the current client context to the current
- * request.
- */
-public class CurrentClientContextFilter implements Filter {
-
-    private final FeatureManager featureManager;
-
-    public CurrentClientContextFilter(final FeatureManager featureManager) {
-        this.featureManager = featureManager;
-    }
-
-    @Override
-    public void init(final FilterConfig config) {
-        // nothing to do
-    }
-
-    @Override
-    public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain)
-            throws IOException, ServletException {
-
-        ClientContext current = this.featureManager.setCurrentClientContext(req);
-        try {
-            chain.doFilter(req, res);
-        } finally {
-            this.featureManager.unsetCurrentClientContext(current);
-        }
-    }
-
-    @Override
-    public void destroy() {
-        // nothing to do
-    }
-}
diff --git a/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java b/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java
index 82f82da..76d40c7 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/ExecutionContextImpl.java
@@ -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 implements ExecutionContext {
     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;
+    }
 }
diff --git a/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java b/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
index b5297a8..c4f6b84 100644
--- a/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
+++ b/src/main/java/org/apache/sling/featureflags/impl/FeatureManager.java
@@ -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;
-
-    @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 void init(ServletConfig config) {
+        this.servletConfig = config;
+    }
+
+    @Override
+    public ServletConfig getServletConfig() {
+        return this.servletConfig;
+    }
+
+    @Override
+    public String getServletInfo() {
+        return "Features";
     }
 
-    @Deactivate
-    private void deactivate() {
-        if (this.services != null) {
-            for (ServiceRegistration service : this.services) {
-                if (service != null) {
-                    service.unregister();
+    @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;
-    }
-
-    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);
+    void pushContext(final HttpServletRequest request) {
+        this.perThreadClientContext.set(new ExecutionContextImpl(request));
     }
 
-    //--- 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);
     }
 
     /**
diff --git a/src/main/java/org/apache/sling/featureflags/impl/FeatureResourceDecorator.java b/src/main/java/org/apache/sling/featureflags/impl/FeatureResourceDecorator.java
deleted file mode 100644
index 4985ab0..0000000
--- a/src/main/java/org/apache/sling/featureflags/impl/FeatureResourceDecorator.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.
- */
-package org.apache.sling.featureflags.impl;
-
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.sling.api.resource.Resource;
-import org.apache.sling.api.resource.ResourceDecorator;
-import org.apache.sling.featureflags.ClientContext;
-
-/**
- * Resource decorator implementing the resource type mapping
- */
-public class FeatureResourceDecorator implements ResourceDecorator {
-
-    private final FeatureManager manager;
-
-    FeatureResourceDecorator(final FeatureManager manager) {
-        this.manager = manager;
-    }
-
-    @Override
-    public Resource decorate(final Resource resource) {
-        Resource result = resource;
-        final ClientContext info = manager.getCurrentClientContext();
-        if (info instanceof ClientContextImpl) {
-            for (ResourceDecorator rd : ((ClientContextImpl) info).getResourceDecorators()) {
-                Resource r = rd.decorate(resource);
-                if (r != null) {
-                    result = r;
-                }
-            }
-        }
-        return result;
-    }
-
-    @Override
-    public Resource decorate(final Resource resource, final HttpServletRequest request) {
-        return this.decorate(resource);
-    }
-}
diff --git a/src/main/java/org/apache/sling/featureflags/impl/FeatureWebConsolePlugin.java b/src/main/java/org/apache/sling/featureflags/impl/FeatureWebConsolePlugin.java
deleted file mode 100644
index ff2b8d7..0000000
--- a/src/main/java/org/apache/sling/featureflags/impl/FeatureWebConsolePlugin.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.
- */
-package org.apache.sling.featureflags.impl;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.featureflags.ExecutionContext;
-import org.apache.sling.featureflags.Feature;
-
-@SuppressWarnings("serial")
-public class FeatureWebConsolePlugin extends HttpServlet {
-
-    private final FeatureManager featureManager;
-
-    FeatureWebConsolePlugin(final FeatureManager featureManager) {
-        this.featureManager = featureManager;
-    }
-
-    @Override
-    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
-        final PrintWriter pw = resp.getWriter();
-        final Feature[] features = this.featureManager.getAvailableFeatures();
-        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 ExecutionContext ctx = createContext(req);
-            for (final Feature feature : features) {
-                pw.printf("<tr><td>%s</td><td>%s</td><td>%s</td></tr>%n", feature.getName(), feature.getDescription(),
-                    feature.isEnabled(ctx));
-            }
-            pw.println("</table>");
-        }
-    }
-
-    private ExecutionContext createContext(final HttpServletRequest req) {
-        return new ExecutionContext() {
-
-            @Override
-            public ResourceResolver getResourceResolver() {
-                return null;
-            }
-
-            @Override
-            public HttpServletRequest getRequest() {
-                return req;
-            }
-        };
-    }
-}
diff --git a/src/main/java/org/apache/sling/featureflags/impl/FeaturesImpl.java b/src/main/java/org/apache/sling/featureflags/impl/FeaturesImpl.java
deleted file mode 100644
index eb67dd6..0000000
--- a/src/main/java/org/apache/sling/featureflags/impl/FeaturesImpl.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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.
- */
-package org.apache.sling.featureflags.impl;
-
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.sling.api.resource.ResourceResolver;
-import org.apache.sling.featureflags.ClientContext;
-import org.apache.sling.featureflags.Feature;
-import org.apache.sling.featureflags.Features;
-
-/**
- * This is a wrapper around the internal feature manager.
- */
-public class FeaturesImpl implements Features {
-
-    private final FeatureManager manager;
-
-    FeaturesImpl(final FeatureManager manager) {
-        this.manager = manager;
-    }
-
-    @Override
-    public String[] getAvailableFeatureNames() {
-        return this.manager.getAvailableFeatureNames();
-    }
-
-    @Override
-    public boolean isAvailable(final String featureName) {
-        return this.manager.isAvailable(featureName);
-    }
-
-    @Override
-    public Feature[] getAvailableFeatures() {
-        return this.manager.getAvailableFeatures();
-    }
-
-    @Override
-    public Feature getFeature(final String name) {
-        return this.manager.getFeature(name);
-    }
-
-    @Override
-    public ClientContext getCurrentClientContext() {
-        return this.manager.getCurrentClientContext();
-    }
-
-    @Override
-    public ClientContext createClientContext(final ResourceResolver resolver) {
-        return this.manager.createClientContext(resolver);
-    }
-
-    @Override
-    public ClientContext createClientContext(final HttpServletRequest request) {
-        return this.manager.createClientContext(request);
-    }
-}
diff --git a/src/main/java/org/apache/sling/featureflags/package-info.java b/src/main/java/org/apache/sling/featureflags/package-info.java
index 41b243d..c1803b5 100644
--- a/src/main/java/org/apache/sling/featureflags/package-info.java
+++ b/src/main/java/org/apache/sling/featureflags/package-info.java
@@ -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>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.