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 <[email protected]> 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 "[email protected]" <[email protected]>.
