SLING-5012 Sling Rewriter: Check unwrapped resources as well for resource type matching

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1702206 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/sling/rewriter/impl/ProcessorConfigurationImpl.java b/src/main/java/org/apache/sling/rewriter/impl/ProcessorConfigurationImpl.java
index 87ef44a..6cd46b9 100644
--- a/src/main/java/org/apache/sling/rewriter/impl/ProcessorConfigurationImpl.java
+++ b/src/main/java/org/apache/sling/rewriter/impl/ProcessorConfigurationImpl.java
@@ -23,7 +23,9 @@
 import java.util.Set;
 
 import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.resource.ResourceWrapper;
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.rewriter.PipelineConfiguration;
 import org.apache.sling.rewriter.ProcessingComponentConfiguration;
@@ -49,6 +51,8 @@
 
     static final String PROPERTY_RESOURCE_TYPES = "resourceTypes";
 
+    static final String PROPERTY_UNWRAP_RESOURCES = "unwrapResources";
+
     static final String PROPERTY_SELECTORS = "selectors";
 
     static final String PROPERTY_TRANFORMERS = "transformerTypes";
@@ -74,6 +78,9 @@
     /** For which resource types should this processor be applied. */
     private final String[] resourceTypes;
 
+    /** Whether unwrapped resources should be validated as well when checking for resource types. */
+    private final boolean unwrapResources;
+
     /** For which selectors should this processor be applied. */
     private final String[] selectors;
 
@@ -112,6 +119,7 @@
                                       String[] paths,
                                       String[] extensions,
                                       String[] resourceTypes,
+                                      boolean unwrapResources,
                                       String[] selectors,
                                       int      order,
                                       ProcessingComponentConfiguration generatorConfig,
@@ -120,6 +128,7 @@
                                       boolean processErrorResponse) {
         this.contentTypes = contentTypes;
         this.resourceTypes = resourceTypes;
+        this.unwrapResources = unwrapResources;
         this.selectors = selectors;
         this.paths = paths;
         this.extensions = extensions;
@@ -143,7 +152,7 @@
                                       String[] extensions,
                                       String[] resourceTypes,
                                       String[] selectors) {
-        this(contentTypes, paths, extensions, resourceTypes, selectors, 0, null, null, null, false);
+        this(contentTypes, paths, extensions, resourceTypes, false, selectors, 0, null, null, null, false);
     }
 
     /**
@@ -154,6 +163,7 @@
         final ValueMap properties = ResourceUtil.getValueMap(resource);
         this.contentTypes = properties.get(PROPERTY_CONTENT_TYPES, String[].class);
         this.resourceTypes = properties.get(PROPERTY_RESOURCE_TYPES, String[].class);
+        this.unwrapResources = properties.get(PROPERTY_UNWRAP_RESOURCES, false);
         this.selectors = properties.get(PROPERTY_SELECTORS, String[].class);
         this.paths = properties.get(PROPERTY_PATHS, String[].class);
         this.extensions = properties.get(PROPERTY_EXTENSIONS, String[].class);
@@ -405,13 +415,21 @@
         }
         // check resource types
         if ( this.resourceTypes != null && this.resourceTypes.length > 0 ) {
+            final ResourceResolver resourceResolver = processContext.getRequest().getResourceResolver();
             final Resource resource = processContext.getRequest().getResource();
             boolean found = false;
             int index = 0;
             while ( !found && index < this.resourceTypes.length ) {
-                if ( ResourceUtil.isA(resource, resourceTypes[index]) ) {
+                if ( resourceResolver.isResourceType(resource, resourceTypes[index]) ) {
                     found = true;
                 }
+                else if ( unwrapResources && resource instanceof ResourceWrapper ) {
+                    // accept resource as well if type was overridden and unwrapped resource has a matching type
+                    final Resource unwrappedResource = unwrap(resource);
+                    if ( resourceResolver.isResourceType(unwrappedResource, resourceTypes[index]) ) {
+                        found = true;
+                    }
+                }
                 index++;
             }
             if ( !found ) {
@@ -466,6 +484,20 @@
     }
 
     /**
+     * Unwrap the resource and return the wrapped implementation.
+     * Copied from ResourceUtil.unwrap which is available in Sling API 2.7.0 and up.
+     * @param rsrc The resource to unwrap
+     * @return The unwrapped resource
+     */
+    private static Resource unwrap(final Resource rsrc) {
+        Resource result = rsrc;
+        while (result instanceof ResourceWrapper) {
+            result = ((ResourceWrapper)result).getResource();
+        }
+        return result;
+    }
+    
+    /**
      * The configuration for the generator.
      */
     public ProcessingComponentConfiguration getGeneratorConfiguration() {
diff --git a/src/test/java/org/apache/sling/rewriter/impl/ProcessorConfigurationImplTest.java b/src/test/java/org/apache/sling/rewriter/impl/ProcessorConfigurationImplTest.java
index 67ddad6..9e65e3c 100644
--- a/src/test/java/org/apache/sling/rewriter/impl/ProcessorConfigurationImplTest.java
+++ b/src/test/java/org/apache/sling/rewriter/impl/ProcessorConfigurationImplTest.java
@@ -21,6 +21,7 @@
 import static org.apache.sling.rewriter.impl.ProcessorConfigurationImpl.PROPERTY_PATHS;
 import static org.apache.sling.rewriter.impl.ProcessorConfigurationImpl.PROPERTY_RESOURCE_TYPES;
 import static org.apache.sling.rewriter.impl.ProcessorConfigurationImpl.PROPERTY_SELECTORS;
+import static org.apache.sling.rewriter.impl.ProcessorConfigurationImpl.PROPERTY_UNWRAP_RESOURCES;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.when;
@@ -28,6 +29,7 @@
 import java.util.Map;
 
 import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceWrapper;
 import org.apache.sling.rewriter.ProcessingContext;
 import org.apache.sling.testing.mock.sling.junit.SlingContext;
 import org.junit.Before;
@@ -110,6 +112,35 @@
     }
 
     @Test
+    public void testMatchAtLeastOneResourceTypeWithResourceWrapper_UnwrapDisabled() {
+        Resource resource = context.create().resource("/content/test", ImmutableMap.<String, Object>of("sling:resourceType", "type/1"));
+        
+        // overwrite resource type via ResourceWrapper
+        Resource resourceWrapper = new ResourceWrapper(resource) {
+            @Override
+            public String getResourceType() { return "/type/override/1"; }
+        };
+        context.currentResource(resourceWrapper);
+        
+        assertNoMatch(ImmutableMap.<String,Object>of(PROPERTY_RESOURCE_TYPES, new String[] {"type/1","type/2"}));
+    }
+
+    @Test
+    public void testMatchAtLeastOneResourceTypeWithResourceWrapper_UnwrapEnabled() {
+        Resource resource = context.create().resource("/content/test", ImmutableMap.<String, Object>of("sling:resourceType", "type/1"));
+        
+        // overwrite resource type via ResourceWrapper
+        Resource resourceWrapper = new ResourceWrapper(resource) {
+            @Override
+            public String getResourceType() { return "/type/override/1"; }
+        };
+        context.currentResource(resourceWrapper);
+        
+        assertMatch(ImmutableMap.<String,Object>of(PROPERTY_RESOURCE_TYPES, new String[] {"type/1","type/2"},
+                PROPERTY_UNWRAP_RESOURCES, true));
+    }
+
+    @Test
     public void testMatchPathMismatch() {
         context.requestPathInfo().setResourcePath("/content/test");
         assertNoMatch(ImmutableMap.<String,Object>of(PROPERTY_PATHS, new String[] {"/apps","/var"}));