SLING-9672 - Expose vanity paths from ResourceMapper.getAllMappings()

Implementation.
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java
index cdc5bcc..3dcc2e0 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntries.java
@@ -636,6 +636,11 @@
     public Map<String, String> getAliasMap(final String parentPath) {
         return aliasMap.get(parentPath);
     }
+    
+    @Override
+    public Map<String, List<String>> getVanityPathMappings() {
+        return Collections.unmodifiableMap(vanityTargets);
+    }
 
     /**
      * get the MapEnty containing all the nodes having a specific vanityPath
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntriesHandler.java b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntriesHandler.java
index df19e5d..b162eb5 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntriesHandler.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/MapEntriesHandler.java
@@ -51,6 +51,11 @@
         public Map<String, String> getAliasMap(String parentPath) {
             return Collections.emptyMap();
         }
+        
+        @Override
+        public Map<String, List<String>> getVanityPathMappings() {
+            return Collections.emptyMap();
+        }
     };
 
     Map<String, String> getAliasMap(String parentPath);
@@ -67,4 +72,13 @@
      * This is for the web console plugin
      */
     List<MapEntry> getResolveMaps();
+    
+    /*
+     * Returns vanity path information
+     * 
+     * <p>Maps resources paths to a list of vanity paths.</p>
+     * 
+     * @return an unmodifiable list of vanity path mappings
+     */
+    Map<String, List<String>> getVanityPathMappings();
 }
diff --git a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImpl.java b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImpl.java
index c7eb908..bc47c26 100644
--- a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImpl.java
+++ b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImpl.java
@@ -160,11 +160,16 @@
             mappings.addAll(aliases);
             populateMappingsFromMapEntries(mappings, aliases, requestContext);
         }
+        
+        // 6. add vanity paths
+        List<String> vanityPaths = mapEntries.getVanityPathMappings().getOrDefault(mappedPath, Collections.emptyList());
+        // vanity paths are prepended to make sure they get returned last
+        mappings.addAll(0, vanityPaths);
 
-        // 6. apply context path if needed
+        // 7. apply context path if needed
         mappings.replaceAll(new ApplyContextPath(request));
        
-        // 7. set back the fragment query if needed
+        // 8. set back the fragment query if needed
         if ( fragmentQuery != null ) {
             mappings.replaceAll(path -> path.concat(fragmentQuery));
         }
diff --git a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImplTest.java b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImplTest.java
index 3b8effa..0e2cc54 100644
--- a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImplTest.java
+++ b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImplTest.java
@@ -47,7 +47,6 @@
 import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -112,7 +111,7 @@
         resourceProvider.putResource("/parent", PROP_ALIAS, "alias-parent"); // parent has alias
         resourceProvider.putResource("/parent/child", PROP_ALIAS, "alias-child"); // child has alias
         resourceProvider.putResource("/parent/child-multiple", PROP_ALIAS, "alias-child-1", "alias-child-2"); // child has multiple alias
-        resourceProvider.putResource("/vain", "sling:vanityPath", "/vanity-a", "/vanity-b");
+        resourceProvider.putResource("/vain", "sling:vanityPath", "/vanity-a", "/vanity-b"); // vanity path
 
         // build /etc/map structure
         resourceProvider.putResource("/etc");
@@ -312,13 +311,18 @@
                 .verify(resolver, req);
     }
     
+    /**
+     * Validates that vanity paths are returned as mappings
+     * 
+     * <p>As vanity paths are alternate paths rather than variations so they will not be returned
+     * from the singleMapping() methods.</p>
+     */
     @Test
-    @Ignore
     public void mapResourceWithVanityPaths() {
         ExpectedMappings.existingResource("/vain")
-            .singleMapping("/vanity-a")
-            .singleMappingWithRequest("/app/vanity-a")
-            .allMappings("/vanity-a", "/vanity-b", "/vani")
+            .singleMapping("/vain")
+            .singleMappingWithRequest("/app/vain")
+            .allMappings("/vanity-a", "/vanity-b", "/vain")
             .allMappingsWithRequest("/app/vanity-a", "/app/vanity-b", "/app/vain")
             .verify(resolver, req);
     }