This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to annotated tag org.apache.sling.resourcemerger-1.0.0 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-resourcemerger.git
commit d3fa422413894cc8cdc2e82fa080b3d0ccef4b31 Author: Carsten Ziegeler <cziege...@apache.org> AuthorDate: Fri Feb 7 13:38:39 2014 +0000 SLING-2986 : Fix resource hiding when parent resource contains attribute but child resource is not available. Reduce resource getting to a minimum git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/extensions/resourcemerger@1565644 13f79535-47bb-0310-9956-ffa450edef68 --- .../sling/resourcemerger/impl/MergedResource.java | 45 +---- .../impl/MergedResourceProvider.java | 199 ++++++++++++++++----- .../sling/resourcemerger/impl/MergedValueMap.java | 49 +++-- .../impl/MergedResourceProviderTest.java | 31 ++-- 4 files changed, 196 insertions(+), 128 deletions(-) diff --git a/src/main/java/org/apache/sling/resourcemerger/impl/MergedResource.java b/src/main/java/org/apache/sling/resourcemerger/impl/MergedResource.java index df1da1a..01a223e 100644 --- a/src/main/java/org/apache/sling/resourcemerger/impl/MergedResource.java +++ b/src/main/java/org/apache/sling/resourcemerger/impl/MergedResource.java @@ -48,19 +48,6 @@ public class MergedResource extends AbstractResource { * Constructor * * @param resolver Resource resolver - * @param mergeRootPath Merge root path - * @param relativePath Relative path - */ - MergedResource(final ResourceResolver resolver, - final String mergeRootPath, - final String relativePath) { - this(resolver, mergeRootPath, relativePath, null); - } - - /** - * Constructor - * - * @param resolver Resource resolver * @param mergeRootPath Merge root path * @param relativePath Relative path * @param mappedResources List of physical mapped resources' paths @@ -68,38 +55,25 @@ public class MergedResource extends AbstractResource { MergedResource(final ResourceResolver resolver, final String mergeRootPath, final String relativePath, - final List<String> mappedResources) { + final List<Resource> mappedResources, + final List<ValueMap> valueMaps) { this.resolver = resolver; this.path = (relativePath.length() == 0 ? mergeRootPath : mergeRootPath + "/" + relativePath); this.relativePath = (relativePath.length() == 0 ? "/" : relativePath); if ( mappedResources != null ) { - this.mappedResources.addAll(mappedResources); + for(final Resource rsrc : mappedResources) { + this.mappedResources.add(rsrc.getPath()); + } } - this.resourceType = this.adaptTo(ValueMap.class).get(ResourceResolver.PROPERTY_RESOURCE_TYPE, this.relativePath); + this.properties = new MergedValueMap(valueMaps); + this.resourceType = this.properties.get(ResourceResolver.PROPERTY_RESOURCE_TYPE, this.relativePath); metadata.put("sling.mergedResource", true); - metadata.put("sling.mappedResources", mappedResources.toArray(new String[mappedResources.size()])); - } - - - // ---- MergedResource interface ------------------------------------------ - - public String getRelativePath() { - return relativePath; + metadata.put("sling.mappedResources", this.mappedResources.toArray(new String[this.mappedResources.size()])); } /** * {@inheritDoc} */ - public Iterable<String> getMappedResources() { - return mappedResources; - } - - - // ---- Resource interface ------------------------------------------------ - - /** - * {@inheritDoc} - */ public String getPath() { return this.path; } @@ -141,9 +115,6 @@ public class MergedResource extends AbstractResource { @SuppressWarnings("unchecked") public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) { if (type == ValueMap.class) { - if ( this.properties == null ) { - this.properties = new MergedValueMap(this); - } return (AdapterType) this.properties; } diff --git a/src/main/java/org/apache/sling/resourcemerger/impl/MergedResourceProvider.java b/src/main/java/org/apache/sling/resourcemerger/impl/MergedResourceProvider.java index a152c2f..ad787a7 100644 --- a/src/main/java/org/apache/sling/resourcemerger/impl/MergedResourceProvider.java +++ b/src/main/java/org/apache/sling/resourcemerger/impl/MergedResourceProvider.java @@ -56,46 +56,100 @@ public class MergedResourceProvider implements ResourceProvider { final String relativePath = getRelativePath(path); if ( relativePath != null ) { - final List<String> mappedResources = new ArrayList<String>(); - // Loop over provided base paths - for (final String basePath : resolver.getSearchPath()) { + final ResourceHolder holder = new ResourceHolder(ResourceUtil.getName(path)); + + // Loop over provided base paths, start with least import + final String[] searchPaths = resolver.getSearchPath(); + for(int i=searchPaths.length-1; i >= 0; i--) { + final String basePath = searchPaths[i]; + // Try to get the corresponding physical resource for this base path - final Resource baseRes = resolver.getResource(basePath + "/" + relativePath); - if (baseRes != null) { - // check if resource is hidden + final String fullPath = basePath + "/" + relativePath; + + // check parent for hiding + final Resource parent = resolver.getResource(ResourceUtil.getParent(fullPath)); + if ( parent != null ) { boolean hidden = false; - final ValueMap props = ResourceUtil.getValueMap(baseRes); - if ( props.get(MergedResourceConstants.PN_HIDE_RESOURCE, Boolean.FALSE) ) { - hidden = true; - } - if ( !hidden ) { - // check parent - final ValueMap parentProps = ResourceUtil.getValueMap(baseRes.getParent()); - final String[] childrenToHideArray = parentProps.get(MergedResourceConstants.PN_HIDE_CHILDREN, String[].class); - if ( childrenToHideArray != null ) { - for(final String name : childrenToHideArray ) { - if ( name.equals(baseRes.getName()) || name.equals("*") ) { - hidden = true; - break; - } + final ValueMap parentProps = ResourceUtil.getValueMap(parent); + final String[] childrenToHideArray = parentProps.get(MergedResourceConstants.PN_HIDE_CHILDREN, String[].class); + if ( childrenToHideArray != null ) { + for(final String name : childrenToHideArray ) { + if ( name.equals(holder.name) || name.equals("*") ) { + hidden = true; + break; } } } - if ( !hidden ) { - // Physical resource exists, add it to the list of mapped resources - mappedResources.add(0, baseRes.getPath()); + if ( hidden ) { + holder.resources.clear(); } else { - mappedResources.clear(); + final Resource baseRes = resolver.getResource(fullPath); + if (baseRes != null) { + holder.resources.add(baseRes); + } } } } + return createMergedResource(resolver, relativePath, holder); + } + + return null; + } + + private static final class ResourceHolder { + public final String name; + public final List<Resource> resources = new ArrayList<Resource>(); + public final List<ValueMap> valueMaps = new ArrayList<ValueMap>(); + + public ResourceHolder(final String n) { + this.name = n; + } + } - if (!mappedResources.isEmpty()) { - // Create a new merged resource based on the list of mapped physical resources - return new MergedResource(resolver, mergeRootPath, relativePath, mappedResources); + /** + * Create the merged resource based on the provided resources + */ + private Resource createMergedResource(final ResourceResolver resolver, + final String relativePath, + final ResourceHolder holder) { + int index = 0; + while ( index < holder.resources.size() ) { + final Resource baseRes = holder.resources.get(index); + // check if resource is hidden + boolean hidden = false; + final ValueMap props = ResourceUtil.getValueMap(baseRes); + holder.valueMaps.add(props); + if ( props.get(MergedResourceConstants.PN_HIDE_RESOURCE, Boolean.FALSE) ) { + hidden = true; + } + if ( !hidden ) { + // check parent + final ValueMap parentProps = ResourceUtil.getValueMap(baseRes.getParent()); + final String[] childrenToHideArray = parentProps.get(MergedResourceConstants.PN_HIDE_CHILDREN, String[].class); + if ( childrenToHideArray != null ) { + for(final String name : childrenToHideArray ) { + if ( name.equals(baseRes.getName()) || name.equals("*") ) { + hidden = true; + break; + } + } + } + } + if ( hidden ) { + // clear everything up to now + for(int i=0;i<=index;i++) { + holder.resources.remove(0); + } + holder.valueMaps.clear(); + index = -1; // start at zero } + index++; } + if (!holder.resources.isEmpty()) { + // create a new merged resource based on the list of mapped physical resources + return new MergedResource(resolver, mergeRootPath, relativePath, holder.resources, holder.valueMaps); + } return null; } @@ -108,35 +162,82 @@ public class MergedResourceProvider implements ResourceProvider { final String relativePath = getRelativePath(resource.getPath()); if ( relativePath != null ) { - final List<String> names = new ArrayList<String>(); - // Loop over provided base paths - for (final String basePath : resolver.getSearchPath()) { - final Resource baseResource = resolver.getResource(basePath + "/" + relativePath); - if ( baseResource != null ) { - for(final Resource child : baseResource.getChildren()) { - final String rsrcName = child.getName(); - if ( !names.contains(rsrcName) ) { - names.add(rsrcName); - } - // Check if children need reordering - int orderBeforeIndex = -1; - final ValueMap vm = ResourceUtil.getValueMap(child); - final String orderBefore = vm.get(MergedResourceConstants.PN_ORDER_BEFORE, String.class); - if (orderBefore != null && !orderBefore.equals(rsrcName)) { - // search entry - orderBeforeIndex = names.indexOf(orderBefore); + final List<ResourceHolder> candidates = new ArrayList<ResourceHolder>(); + + // Loop over provided base paths, start with least import + final String[] searchPaths = resolver.getSearchPath(); + for(int i=searchPaths.length-1; i >= 0; i--) { + final String basePath = searchPaths[i]; + final Resource parentResource = resolver.getResource(basePath + "/" + relativePath); + if ( parentResource != null ) { + final ValueMap parentProps = ResourceUtil.getValueMap(parentResource); + List<String> childrenToHide = new ArrayList<String>(); + boolean hideAll = false; + final String[] childrenToHideArray = parentProps.get(MergedResourceConstants.PN_HIDE_CHILDREN, String[].class); + if ( childrenToHideArray != null ) { + for(final String name : childrenToHideArray ) { + if ( name.equals("*") ) { + hideAll = true; + } else { + childrenToHide.add(name); + } } + } + if ( hideAll ) { + candidates.clear(); + } else { + for(final Resource child : parentResource.getChildren()) { + final String rsrcName = child.getName(); + ResourceHolder holder = null; + for(final ResourceHolder current : candidates) { + if ( current.name.equals(rsrcName) ) { + holder = current; + break; + } + } + if ( holder == null ) { + holder = new ResourceHolder(rsrcName); + candidates.add(holder); + } + holder.resources.add(child); + + // Check if children need reordering + int orderBeforeIndex = -1; + final ValueMap vm = ResourceUtil.getValueMap(child); + final String orderBefore = vm.get(MergedResourceConstants.PN_ORDER_BEFORE, String.class); + if (orderBefore != null && !orderBefore.equals(rsrcName)) { + // search entry + int index = 0; + while (index < candidates.size()) { + final ResourceHolder current = candidates.get(index); + if ( current.name.equals(orderBefore) ) { + orderBeforeIndex = index; + break; + } + index++; + } + } - if (orderBeforeIndex > -1) { - names.add(orderBeforeIndex, rsrcName); - names.remove(names.size() - 1); + if (orderBeforeIndex > -1) { + candidates.add(orderBeforeIndex, holder); + candidates.remove(candidates.size() - 1); + } + } + if ( childrenToHide.size() > 0 ) { + final Iterator<ResourceHolder> iter = candidates.iterator(); + while ( iter.hasNext() ) { + final ResourceHolder holder = iter.next(); + if ( childrenToHide.contains(holder.name) ) { + iter.remove(); + } + } } } } } final List<Resource> children = new ArrayList<Resource>(); - for(final String name : names) { - final Resource mergedResource = this.getResource(resolver, resource.getPath() + "/" + name); + for(final ResourceHolder holder : candidates) { + final Resource mergedResource = this.createMergedResource(resolver, relativePath + '/' + holder.name, holder); if ( mergedResource != null ) { children.add(mergedResource); } diff --git a/src/main/java/org/apache/sling/resourcemerger/impl/MergedValueMap.java b/src/main/java/org/apache/sling/resourcemerger/impl/MergedValueMap.java index 3a888fa..4bb186d 100644 --- a/src/main/java/org/apache/sling/resourcemerger/impl/MergedValueMap.java +++ b/src/main/java/org/apache/sling/resourcemerger/impl/MergedValueMap.java @@ -20,10 +20,9 @@ package org.apache.sling.resourcemerger.impl; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Set; -import org.apache.sling.api.resource.Resource; -import org.apache.sling.api.resource.ResourceUtil; import org.apache.sling.api.resource.ValueMap; import org.apache.sling.api.wrappers.ValueMapDecorator; @@ -50,34 +49,30 @@ public class MergedValueMap extends ValueMapDecorator { * * @param resource The merged resource to get properties from */ - public MergedValueMap(final MergedResource resource) { + public MergedValueMap(final List<ValueMap> valueMaps) { super(new HashMap<String, Object>()); - // Iterate over physical resources - for (final String r : resource.getMappedResources()) { - final Resource rsrc = resource.getResourceResolver().getResource(r); - if ( rsrc != null ) { - final ValueMap vm = ResourceUtil.getValueMap(rsrc); - if (this.isEmpty()) { - // Add all properties - this.putAll(vm); - } else { - // Get properties to add or override - for (final String key : vm.keySet()) { - if (!isExcludedProperty(key)) { - this.put(key, vm.get(key)); - } + // Iterate over value maps + for (final ValueMap vm : valueMaps) { + if (this.isEmpty()) { + // Add all properties + this.putAll(vm); + } else { + // Get properties to add or override + for (final String key : vm.keySet()) { + if (!isExcludedProperty(key)) { + this.put(key, vm.get(key)); } + } - // Get properties to hide - final String[] propertiesToHide = vm.get(MergedResourceConstants.PN_HIDE_PROPERTIES, String[].class); - if ( propertiesToHide != null ) { - for (final String propName : propertiesToHide) { - if (propName.equals("*")) { - this.clear(); - break; - } else { - this.remove(propName); - } + // Get properties to hide + final String[] propertiesToHide = vm.get(MergedResourceConstants.PN_HIDE_PROPERTIES, String[].class); + if ( propertiesToHide != null ) { + for (final String propName : propertiesToHide) { + if (propName.equals("*")) { + this.clear(); + break; + } else { + this.remove(propName); } } } diff --git a/src/test/java/org/apache/sling/resourcemerger/impl/MergedResourceProviderTest.java b/src/test/java/org/apache/sling/resourcemerger/impl/MergedResourceProviderTest.java index e6d703f..08bbab2 100644 --- a/src/test/java/org/apache/sling/resourcemerger/impl/MergedResourceProviderTest.java +++ b/src/test/java/org/apache/sling/resourcemerger/impl/MergedResourceProviderTest.java @@ -45,25 +45,26 @@ public class MergedResourceProviderTest { final ResourceResolverFactory factory = new MockResourceResolverFactory(); this.resolver = factory.getAdministrativeResourceResolver(null); MockHelper.create(this.resolver).resource("/apps") - .resource("a") + .resource("a").p(MergedResourceConstants.PN_HIDE_CHILDREN, new String[] {"Z", "x", "y"}) .resource("1").p("a", "1").p("b", "2") - .resource("./2").p(ResourceResolver.PROPERTY_RESOURCE_TYPE, "apps") - .resource("./3").p("e", "2") - .p(MergedResourceConstants.PN_HIDE_PROPERTIES, "*") - .p("b", "x") - .p("d", "1") - .resource("./4").p("e", "2") - .p(MergedResourceConstants.PN_HIDE_PROPERTIES, new String[] {"a", "c"}) - .p("b", "x") - .p("d", "1") - .resource("./X") + .resource(".2").p(ResourceResolver.PROPERTY_RESOURCE_TYPE, "apps") + .resource(".3").p("e", "2") + .p(MergedResourceConstants.PN_HIDE_PROPERTIES, "*") + .p("b", "x") + .p("d", "1") + .resource(".4").p("e", "2") + .p(MergedResourceConstants.PN_HIDE_PROPERTIES, new String[] {"a", "c"}) + .p("b", "x") + .p("d", "1") + .resource(".X") .resource("/libs") .resource("a") .resource("1").p("a", "5").p("c", "2") - .resource("./2").p(ResourceResolver.PROPERTY_RESOURCE_TYPE, "libs") - .resource("./3").p("a", "1").p("b", "2").p("c", "3") - .resource("./4").p("a", "1").p("b", "2").p("c", "3") - .resource("./Y") + .resource(".2").p(ResourceResolver.PROPERTY_RESOURCE_TYPE, "libs") + .resource(".3").p("a", "1").p("b", "2").p("c", "3") + .resource(".4").p("a", "1").p("b", "2").p("c", "3") + .resource(".Y") + .resource(".Z") .commit(); this.provider = new MergedResourceProvider("/merged"); -- To stop receiving notification emails like this one, please contact "commits@sling.apache.org" <commits@sling.apache.org>.