You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by as...@apache.org on 2015/01/09 10:52:02 UTC

svn commit: r1650470 [2/2] - /sling/trunk/launchpad/test-services/src/main/java/org/apache/sling/launchpad/testservices/serversidetests/ResourceResolverWithVanityBloomFilterTest.java

Added: sling/trunk/launchpad/test-services/src/main/java/org/apache/sling/launchpad/testservices/serversidetests/ResourceResolverWithVanityBloomFilterTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/test-services/src/main/java/org/apache/sling/launchpad/testservices/serversidetests/ResourceResolverWithVanityBloomFilterTest.java?rev=1650470&view=auto
==============================================================================
--- sling/trunk/launchpad/test-services/src/main/java/org/apache/sling/launchpad/testservices/serversidetests/ResourceResolverWithVanityBloomFilterTest.java (added)
+++ sling/trunk/launchpad/test-services/src/main/java/org/apache/sling/launchpad/testservices/serversidetests/ResourceResolverWithVanityBloomFilterTest.java Fri Jan  9 09:52:02 2015
@@ -0,0 +1,2835 @@
+/*
+ * 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.launchpad.testservices.serversidetests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.sling.api.resource.NonExistingResource;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.junit.annotations.SlingAnnotationsTestRunner;
+import org.apache.sling.junit.annotations.TestReference;
+import org.apache.sling.launchpad.testservices.events.EventsCounter;
+import org.apache.sling.launchpad.testservices.exported.FakeSlingHttpServletRequest;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@RunWith(SlingAnnotationsTestRunner.class)
+public class ResourceResolverWithVanityBloomFilterTest {
+
+    public static final String PROP_REDIRECT_INTERNAL = "sling:internalRedirect";
+    public static final String PROP_REDIRECT_EXTERNAL = "sling:redirect";
+    public static final String MAPPING_EVENT_TOPIC = "org/apache/sling/api/resource/ResourceResolverMapping/CHANGED";
+
+    private static final Logger logger = LoggerFactory.getLogger(ResourceResolverWithVanityBloomFilterTest.class);
+    private static ResourceResolver resResolver;
+    private static Session session;
+    private String rootPath;
+    private Node rootNode;
+    private Node mapRoot;
+    private String [] vanity;
+    private static List<String> toDelete = new ArrayList<String>();
+    private static ResourceResolverFactory cleanupResolverFactory;
+    private MappingsFacade mappingsFacade;
+    
+    @TestReference
+    private EventsCounter eventsCounter;
+    
+    @TestReference
+    private ResourceResolverFactory resourceResolverFactory;  
+    
+    private Node maybeCreateNode(Node parent, String name, String type) throws RepositoryException {
+        if(parent.hasNode(name)) {
+            return parent.getNode(name);
+        } else {
+            return parent.addNode(name, type);
+        }
+    }
+    
+    private void saveMappings(Session s) throws Exception {
+        final String saveMappingsError = mappingsFacade.saveMappings(s);
+        if(saveMappingsError != null) {
+            fail(saveMappingsError);
+        }
+    }
+
+    @Before
+    public synchronized void setup() throws Exception {
+        closeResolver();
+        resResolver = resourceResolverFactory.getAdministrativeResourceResolver(null);
+        setMaxCachedVanityPathEntries(0);
+        cleanupResolverFactory = resourceResolverFactory;
+        session = resResolver.adaptTo(Session.class);
+        mappingsFacade = new MappingsFacade(eventsCounter);
+        
+        // Do the mappings setup only once, and clean it up 
+        // after all tests
+        rootNode = maybeCreateNode(session.getRootNode(), "content", "nt:unstructured");
+        rootPath = rootNode.getPath();
+        session.save();
+        if(toDelete.isEmpty()) {
+            final Node mapRoot = maybeCreateNode(session.getRootNode(), "etc", "nt:folder");
+            final Node map = maybeCreateNode(mapRoot, "map", "sling:Mapping");
+            final Node http = maybeCreateNode(map, "http", "sling:Mapping");
+            maybeCreateNode(http, "localhost.80", "sling:Mapping");
+            final Node https = maybeCreateNode(map, "https", "sling:Mapping");
+            maybeCreateNode(https, "localhost.443", "sling:Mapping");
+            toDelete.add(map.getPath());
+            toDelete.add(rootNode.getPath());
+        }
+        
+        mapRoot = session.getNode("/etc");
+        session.save();
+        
+        // define a vanity path for the rootPath
+        vanity = new String[] {"testVanity","testV", "testVanityToUpdate"};
+        rootNode.setProperty("sling:vanityPath", vanity);
+        rootNode.addMixin("sling:VanityPath");
+        saveMappings(session);
+    }
+    
+    private void closeResolver() {
+        if(session != null) {
+            if(session.isLive()) {
+                session.logout();
+            }
+            session = null;
+        }
+        if (resResolver != null ) {
+            resResolver.close();
+            resResolver = null;
+        }
+        
+    }
+    
+    private void setMaxCachedVanityPathEntries(long maxCachedVanityPathEntries) throws Exception{
+        //FIXME: enabling bloom filter usage using reflection for now
+        // we need to have a new mechanism to test different then default OSGi configurations
+        Field commonFactory = resourceResolverFactory.getClass().getDeclaredField("commonFactory");
+        commonFactory.setAccessible(true);
+        Object commonResourceResolverFactoryImpl = commonFactory.get(resourceResolverFactory);        
+        Field mapEntries = commonResourceResolverFactoryImpl.getClass().getDeclaredField("mapEntries");
+        mapEntries.setAccessible(true);
+        Object  mapEntriesObject = mapEntries.get(commonResourceResolverFactoryImpl);        
+        Field maxCachedVanityPathEntriesField = mapEntriesObject.getClass().getDeclaredField("maxCachedVanityPathEntries");
+        maxCachedVanityPathEntriesField.setAccessible(true); 
+        maxCachedVanityPathEntriesField.setLong(mapEntriesObject, maxCachedVanityPathEntries);
+    }
+
+    @After
+    public void deleteTestNodes() throws Exception {
+        logger.debug("{} test done, deleting test nodes", ResourceResolverWithVanityBloomFilterTest.class.getSimpleName());
+        setMaxCachedVanityPathEntries(-1);
+        final ResourceResolver resolver = cleanupResolverFactory.getAdministrativeResourceResolver(null);
+        final Session session = resolver.adaptTo(Session.class);
+        
+        try {
+            for(String path : toDelete) {
+                if(session.itemExists(path)) {
+                    session.getItem(path).remove();
+                }
+            }
+            toDelete.clear();
+            session.save();
+        } finally {
+            session.logout();
+            resolver.close();
+        }
+    }
+    
+    @Test public void test_clone_based_on_anonymous() throws Exception {
+        final ResourceResolver anon0 = this.resourceResolverFactory.getResourceResolver((Map<String, Object>) null);
+        final Session anon0Session = anon0.adaptTo(Session.class);
+        assertEquals("anonymous", anon0.getUserID());
+
+        // same user and workspace
+        final ResourceResolver anon1 = anon0.clone(null);
+        final Session anon1Session = anon1.adaptTo(Session.class);
+        assertEquals(anon0.getUserID(), anon1.getUserID());
+        assertEquals(anon0Session.getWorkspace().getName(),
+            anon1Session.getWorkspace().getName());
+        anon1.close();
+
+        // same workspace but admin user
+        final Map<String, Object> admin0Cred = new HashMap<String, Object>();
+        admin0Cred.put(ResourceResolverFactory.USER, "admin");
+        admin0Cred.put(ResourceResolverFactory.PASSWORD, "admin".toCharArray());
+        final ResourceResolver admin0 = anon0.clone(admin0Cred);
+        final Session admin0Session = admin0.adaptTo(Session.class);
+        assertEquals("admin", admin0.getUserID());
+        assertEquals(anon0Session.getWorkspace().getName(),
+            admin0Session.getWorkspace().getName());
+        admin0.close();
+
+        // same user but different workspace
+        final Map<String, Object> anon2Cred = new HashMap<String, Object>();
+        final ResourceResolver anon2 = anon0.clone(anon2Cred);
+        assertEquals("anonymous", anon2.getUserID());
+        anon2.close();
+
+        // different user and workspace
+        final Map<String, Object> admin1Cred = new HashMap<String, Object>();
+        admin1Cred.put(ResourceResolverFactory.USER, "admin");
+        admin1Cred.put(ResourceResolverFactory.PASSWORD, "admin".toCharArray());
+        final ResourceResolver admin1 = anon0.clone(admin1Cred);
+        assertEquals("admin", admin1.getUserID());
+        admin1.close();
+
+        anon0.close();
+    }
+
+    @Test public void test_clone_based_on_admin() throws Exception {
+        final ResourceResolver admin0 = this.resourceResolverFactory.getAdministrativeResourceResolver((Map<String, Object>) null);
+        final Session admin0Session = admin0.adaptTo(Session.class);
+        assertEquals("admin", admin0.getUserID());
+
+        // same user and workspace
+        final ResourceResolver admin1 = admin0.clone(null);
+        final Session admin1Session = admin1.adaptTo(Session.class);
+        assertEquals(admin0.getUserID(), admin1.getUserID());
+        assertEquals(admin0Session.getWorkspace().getName(),
+            admin1Session.getWorkspace().getName());
+        admin1.close();
+
+        // same workspace but anonymous user
+        final Map<String, Object> anon0Cred = new HashMap<String, Object>();
+        anon0Cred.put(ResourceResolverFactory.USER, "anonymous");
+        final ResourceResolver anon0 = admin0.clone(anon0Cred);
+        final Session anon0Session = anon0.adaptTo(Session.class);
+        assertEquals("anonymous", anon0.getUserID());
+        assertEquals(admin0Session.getWorkspace().getName(),
+            anon0Session.getWorkspace().getName());
+        anon0.close();
+
+        // same user but different workspace
+        final Map<String, Object> admin2Cred = new HashMap<String, Object>();
+        final ResourceResolver admin2 = admin0.clone(admin2Cred);
+        assertEquals("admin", admin2.getUserID());
+        admin2.close();
+
+        // different user and workspace
+        final Map<String, Object> anon1Cred = new HashMap<String, Object>();
+        anon1Cred.put(ResourceResolverFactory.USER, "anonymous");
+        final ResourceResolver anon1 = admin0.clone(anon1Cred);
+        assertEquals("anonymous", anon1.getUserID());
+        anon1.close();
+
+        admin0.close();
+    }
+
+    /*@Test public void test_attributes_from_session() throws Exception {
+        // test assumes admin password is admin (which is default)
+
+        final Credentials creds0 = new SimpleCredentials("admin",
+            "admin".toCharArray());
+        final Session session0 = getRepository().login(creds0);
+        final Map<String, Object> authInfo = new HashMap<String, Object>();
+        authInfo.put(ResourceResolverFactory.USER, "admin");
+        authInfo.put(ResourceResolverFactory.PASSWORD, "admin".toCharArray());
+        authInfo.put("testAttributeString", "AStringValue");
+        authInfo.put("testAttributeNumber", 999);
+
+        final ResourceResolver resolver0 = resFac.getResourceResolver(authInfo);
+
+        final Iterator<String> attrNames0 = resolver0.getAttributeNames();
+        assertTrue("Expected one attribute", attrNames0.hasNext());
+        final String attrName0 = attrNames0.next();
+        assertEquals("Expected attribute name to address session",
+            JcrResourceConstants.AUTHENTICATION_INFO_SESSION, attrName0);
+        assertFalse("Expected no more attributes", attrNames0.hasNext());
+        assertEquals("Expected session attribute to be the session", session0,
+            resolver0.getAttribute(attrName0));
+
+        assertEquals("Expected no Session attributes", 0,
+            session0.getAttributeNames().length);
+
+        resolver0.close();
+        assertTrue("Expect session to still be live after resolver close",
+            session0.isLive());
+        session0.logout();
+
+        final SimpleCredentials creds1 = new SimpleCredentials("admin",
+            "admin".toCharArray());
+        creds1.setAttribute("testAttributeString", "AStringValue");
+        creds1.setAttribute("testAttributeNumber", 999);
+        final Session session1 = getRepository().login(creds1);
+
+        final ResourceResolver resolver1 = resFac.getResourceResolver(authInfo);
+
+        assertEquals("Expected 2 Session attributes", 2,
+            session1.getAttributeNames().length);
+        assertEquals("AStringValue",
+            session1.getAttribute("testAttributeString"));
+        assertEquals(999, session1.getAttribute("testAttributeNumber"));
+
+        assertEquals(
+            session1,
+            resolver1.getAttribute(JcrResourceConstants.AUTHENTICATION_INFO_SESSION));
+        assertEquals("AStringValue",
+            resolver1.getAttribute("testAttributeString"));
+        assertEquals(999, resolver1.getAttribute("testAttributeNumber"));
+
+        final Iterator<String> attrNames1 = resolver1.getAttributeNames();
+        assertTrue("Expecting first attribute", attrNames1.hasNext());
+        attrNames1.next();
+        assertTrue("Expecting second attribute", attrNames1.hasNext());
+        attrNames1.next();
+        assertTrue("Expecting third attribute", attrNames1.hasNext());
+        attrNames1.next();
+        assertFalse("Expecting no more attribute", attrNames1.hasNext());
+
+        resolver1.close();
+        assertTrue("Expect session to still be live after resolver close",
+            session1.isLive());
+        session1.logout();
+    }*/
+
+    @Test public void test_attributes_from_authInfo() throws Exception {
+        final Map<String, Object> authInfo = new HashMap<String, Object>();
+        authInfo.put(ResourceResolverFactory.USER, "admin");
+        authInfo.put(ResourceResolverFactory.PASSWORD, "admin".toCharArray());
+        authInfo.put("testAttributeString", "AStringValue");
+        authInfo.put("testAttributeNumber", 999);
+        final ResourceResolver rr = this.resourceResolverFactory.getResourceResolver(authInfo);
+        final Session s = rr.adaptTo(Session.class);
+
+        try {
+            assertEquals("Expect 3 session attributes", 3,
+                s.getAttributeNames().length);
+            assertEquals("AStringValue", s.getAttribute("testAttributeString"));
+            assertEquals(999, s.getAttribute("testAttributeNumber"));
+            assertEquals("admin", s.getAttribute(ResourceResolverFactory.USER));
+            assertNull(session.getAttribute(ResourceResolverFactory.PASSWORD));
+
+            assertEquals("AStringValue", rr.getAttribute("testAttributeString"));
+            assertEquals(999, rr.getAttribute("testAttributeNumber"));
+            assertEquals("admin", rr.getAttribute(ResourceResolverFactory.USER));
+            assertNull(rr.getAttribute(ResourceResolverFactory.PASSWORD));
+
+            final HashSet<String> validNames = new HashSet<String>();
+            validNames.add(ResourceResolverFactory.USER);
+            validNames.add("testAttributeString");
+            validNames.add("testAttributeNumber");
+            final Iterator<String> names = rr.getAttributeNames();
+            assertTrue(validNames.remove(names.next()));
+            assertTrue(validNames.remove(names.next()));
+            assertTrue(validNames.remove(names.next()));
+            assertFalse("Expect no more names", names.hasNext());
+            assertTrue("Expect validNames set to be empty now",
+                validNames.isEmpty());
+        } finally {
+            rr.close();
+        }
+    }
+
+    @Test public void testGetResource() throws Exception {
+        // existing resource
+        Resource res = resResolver.getResource(rootPath);
+        assertNotNull(res);
+        assertEquals(rootPath, res.getPath());
+        assertEquals(rootNode.getPrimaryNodeType().getName(),
+            res.getResourceType());
+
+        assertNotNull(res.adaptTo(Node.class));
+        assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+        // missing resource
+        String path = rootPath + "/missing";
+        res = resResolver.getResource(path);
+        assertNull(res);
+    }
+
+    @Test public void testResolveResource() throws Exception {
+        // existing resource
+        HttpServletRequest request = new FakeSlingHttpServletRequest(rootPath);
+        Resource res = resResolver.resolve(request, rootPath);
+        assertNotNull(res);
+        assertEquals(rootPath, res.getPath());
+        assertEquals(rootNode.getPrimaryNodeType().getName(),
+            res.getResourceType());
+
+        assertNotNull(res.adaptTo(Node.class));
+        assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+        // missing resource below root should resolve "missing resource"
+        String path = rootPath + "/missing";
+        res = resResolver.resolve(new FakeSlingHttpServletRequest(path), path);
+        assertNotNull(res);
+        assertEquals(path, res.getPath());
+        assertEquals(Resource.RESOURCE_TYPE_NON_EXISTING, res.getResourceType());
+
+        assertNull(res.adaptTo(Node.class));
+
+        // root with selectors/ext should resolve root
+        path = rootPath + ".print.a4.html";
+        res = resResolver.resolve(new FakeSlingHttpServletRequest(path), path);
+        assertNotNull(res);
+        assertEquals(rootPath, res.getPath());
+        assertEquals(rootNode.getPrimaryNodeType().getName(),
+            res.getResourceType());
+
+        assertNotNull(res.adaptTo(Node.class));
+        assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+        // missing resource should return NON_EXISTING Resource
+        path = rootPath + System.currentTimeMillis();
+        res = resResolver.resolve(new FakeSlingHttpServletRequest(path), path);
+        assertNotNull(res);
+        assertTrue(ResourceUtil.isNonExistingResource(res));
+        assertEquals(path, res.getPath());
+        assertEquals(Resource.RESOURCE_TYPE_NON_EXISTING, res.getResourceType());
+    }
+
+
+
+    @Test public void testResolveResourceExternalRedirect() throws Exception {
+        HttpServletRequest request = new FakeSlingHttpServletRequest("https",
+            null, -1, rootPath);
+        Node localhost443 = mapRoot.getNode("map/https/localhost.443");
+        localhost443.setProperty(PROP_REDIRECT_EXTERNAL,
+            "http://localhost");
+
+        try {
+            saveMappings(session);
+            Resource res = resResolver.resolve(request, rootPath);
+            assertNotNull(res);
+            assertEquals(rootPath, res.getPath());
+            assertEquals("sling:redirect", res.getResourceType());
+            assertNotNull(res.adaptTo(ValueMap.class));
+            assertEquals("http://localhost" + rootPath,
+                res.adaptTo(ValueMap.class).get("sling:target", String.class));
+        } finally {
+            localhost443.getProperty(PROP_REDIRECT_EXTERNAL).remove();
+            session.save();
+        }
+    }
+
+    @Test public void testResolveResourceInternalRedirectUrl() throws Exception {
+        HttpServletRequest request = new FakeSlingHttpServletRequest("https",
+            null, -1, rootPath);
+        Node localhost443 = mapRoot.getNode("map/https/localhost.443");
+        localhost443.setProperty(PROP_REDIRECT_INTERNAL,
+            "http://localhost");
+
+        try {
+            saveMappings(session);
+            Resource res = resResolver.resolve(request, rootPath);
+            assertNotNull(res);
+            assertEquals(rootPath, res.getPath());
+            assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+        } finally {
+            localhost443.getProperty(PROP_REDIRECT_INTERNAL).remove();
+            session.save();
+        }
+    }
+
+    @Test public void testResolveResourceInternalRedirectPath() throws Exception {
+        HttpServletRequest request = new FakeSlingHttpServletRequest("https",
+            null, -1, rootPath);
+        Node localhost443 = mapRoot.getNode("map/https/localhost.443");
+
+        Node toContent = localhost443.addNode("_playground_designground_",
+            "sling:Mapping");
+        toContent.setProperty("sling:match",
+            "(playground|designground)");
+        toContent.setProperty(PROP_REDIRECT_INTERNAL,
+            "/content/$1");
+        try {
+            saveMappings(session);
+            Resource res = resResolver.resolve(request, "/playground.html");
+            assertNotNull(res);
+            assertEquals("/content/playground.html", res.getPath());
+
+            res = resResolver.resolve(request, "/playground/en.html");
+            assertNotNull(res);
+            assertEquals("/content/playground/en.html", res.getPath());
+
+            res = resResolver.resolve(request, "/libs/nt/folder.html");
+            assertNotNull(res);
+            assertEquals("/libs/nt/folder.html", res.getPath());
+        } finally {
+            toContent.remove();
+            session.save();
+        }
+    }
+    
+    @Test public void testResolveResourceInternalRedirectPathAndVanityPath() throws Exception {
+        HttpServletRequest request = new FakeSlingHttpServletRequest("https",
+                null, -1, rootPath);
+        Node localhost443 = mapRoot.getNode("map/https/localhost.443");
+
+        localhost443.setProperty(PROP_REDIRECT_INTERNAL,
+                "/example");
+        try {
+            saveMappings(session);
+            Resource res = resResolver.resolve(request, vanity[0]);
+            assertNotNull(res);
+            assertEquals(rootPath, res.getPath());
+            
+            //see SLING-3428
+            res = resResolver.resolve(request, vanity[1]);
+            assertNotNull(res);
+            assertEquals("/example/"+vanity[1], res.getPath());
+        } finally {
+            localhost443.getProperty(PROP_REDIRECT_INTERNAL).remove();
+            session.save();
+        }     
+    }
+
+    @Test public void testResolveResourceInternalRedirectPathUpdate() throws Exception {
+        HttpServletRequest request = new FakeSlingHttpServletRequest("https", null, -1, rootPath);
+        Node localhost443 = mapRoot.getNode("map/https/localhost.443");
+        Node toContent = localhost443.addNode("_playground_designground_", "sling:Mapping");
+        toContent.setProperty("sling:match", "(playground|designground)");
+        toContent.setProperty(PROP_REDIRECT_INTERNAL, "/content/$1");
+
+        try {
+            saveMappings(session);
+            Resource res = resResolver.resolve(request, "/playground.html");
+            assertNotNull(res);
+            assertEquals("/content/playground.html", res.getPath());
+
+            res = resResolver.resolve(request, "/playground/en.html");
+            assertNotNull(res);
+            assertEquals("/content/playground/en.html", res.getPath());
+
+            res = resResolver.resolve(request, "/libs/nt/folder.html");
+            assertNotNull(res);
+            assertEquals("/libs/nt/folder.html", res.getPath());
+
+            // update the match
+            toContent.setProperty("sling:match", "(homeground|foreignground)");
+            saveMappings(session);
+
+            res = resResolver.resolve(request, "/homeground.html");
+            assertNotNull(res);
+            assertEquals("/content/homeground.html", res.getPath());
+
+            res = resResolver.resolve(request, "/foreignground/en.html");
+            assertNotNull(res);
+            assertEquals("/content/foreignground/en.html", res.getPath());
+
+            res = resResolver.resolve(request, "/libs/nt/folder.html");
+            assertNotNull(res);
+            assertEquals("/libs/nt/folder.html", res.getPath());
+        } finally {
+            toContent.remove();
+            session.save();
+        }
+    }
+
+    @Test public void testResolveResourceInternalRedirectExact() throws Exception {
+        HttpServletRequest request = new FakeSlingHttpServletRequest("https",
+            null, -1, rootPath);
+        Node localhost443 = mapRoot.getNode("map/https/localhost.443");
+        Node toContent = localhost443.addNode("virtual", "sling:Mapping");
+        toContent.setProperty("sling:match", "virtual$");
+        toContent.setProperty(PROP_REDIRECT_INTERNAL,
+            "/content/virtual.html");
+
+        try {
+            saveMappings(session);
+            Resource res = resResolver.resolve(request, "/virtual");
+            assertNotNull(res);
+            assertEquals("/content/virtual.html", res.getPath());
+
+            res = resResolver.resolve(request, "/virtual.html");
+            assertNotNull(res);
+            assertEquals("/virtual.html", res.getPath());
+
+            res = resResolver.resolve(request, "/virtual/child.html");
+            assertNotNull(res);
+            assertEquals("/virtual/child.html", res.getPath());
+
+            String url = resResolver.map(null, "/content/virtual.html");
+            assertNotNull(url);
+            assertEquals("https://localhost/virtual", url);
+
+            url = resResolver.map(request, "/content/virtual.html");
+            assertNotNull(url);
+            assertEquals("/virtual", url);
+        } finally {
+            toContent.remove();
+            session.save();
+        }
+    }
+
+    @Test public void testResolveResourceInternalRedirectDepthFirst()
+            throws Exception {
+        HttpServletRequest request = new FakeSlingHttpServletRequest("https",
+            null, -1, rootPath);
+
+        // map anything
+        Node localhost443 = mapRoot.getNode("map/https/localhost.443");
+        localhost443.setProperty(PROP_REDIRECT_INTERNAL,
+            "/content2");
+
+        // map only ../virtual
+        Node toContent = localhost443.addNode("virtual", "sling:Mapping");
+        toContent.setProperty("sling:match", "virtual$");
+        toContent.setProperty(PROP_REDIRECT_INTERNAL,
+            "/content2/virtual.html");
+
+        try {
+            saveMappings(session);
+            Resource res = resResolver.resolve(request, "/virtual");
+            assertNotNull(res);
+            assertEquals("/content2/virtual.html", res.getPath());
+
+            res = resResolver.resolve(request, "/virtual.html");
+            assertNotNull(res);
+            assertEquals("/content2/virtual.html", res.getPath());
+
+            res = resResolver.resolve(request, "/virtual/child.html");
+            assertNotNull(res);
+            assertEquals("/content2/virtual/child.html", res.getPath());
+        } finally {
+            localhost443.getProperty(PROP_REDIRECT_INTERNAL).remove();
+            toContent.remove();
+            session.save();
+        }
+    }
+
+    @Test public void testResolveVirtualHostHttp80() throws Exception {
+        HttpServletRequest request = new FakeSlingHttpServletRequest(null,
+            "virtual.host.com", -1, rootPath);
+        Node virtualhost80 = mapRoot.getNode("map/http").addNode(
+            "virtual.host.com.80", "sling:Mapping");
+        virtualhost80.setProperty(PROP_REDIRECT_INTERNAL,
+            "/content/virtual");
+
+        try {
+            saveMappings(session);
+            final Resource res0 = resResolver.resolve(request, "/playground.html");
+            assertNotNull(res0);
+            assertEquals("/content/virtual/playground.html", res0.getPath());
+
+            final Resource res1 = resResolver.resolve(request,
+                "/playground/en.html");
+            assertNotNull(res1);
+            assertEquals("/content/virtual/playground/en.html", res1.getPath());
+
+            final String mapped00 = resResolver.map(res0.getPath());
+            assertEquals("http://virtual.host.com/playground.html", mapped00);
+            final String mapped01 = resResolver.map(request, res0.getPath());
+            assertEquals("/playground.html", mapped01);
+
+            final String mapped10 = resResolver.map(res1.getPath());
+            assertEquals("http://virtual.host.com/playground/en.html", mapped10);
+            final String mapped11 = resResolver.map(request, res1.getPath());
+            assertEquals("/playground/en.html", mapped11);
+        } finally {
+            virtualhost80.remove();
+            session.save();
+        }
+    }
+
+    @Test public void testResolveVirtualHostHttp80Multiple() throws Exception {
+
+        final String de = "de";
+        final String en = "en";
+        final String hostDE = de + ".host.com";
+        final String hostEN = en + ".host.com";
+        final String contentDE = "/content/" + de;
+        final String contentEN = "/content/" + en;
+
+        Node virtualhost80a = mapRoot.getNode("map/http").addNode(
+            hostDE + ".80", "sling:Mapping");
+        virtualhost80a.setProperty(PROP_REDIRECT_INTERNAL,
+            contentDE);
+        Node virtualhost80 = mapRoot.getNode("map/http").addNode(hostEN + ".80",
+            "sling:Mapping");
+        virtualhost80.setProperty(PROP_REDIRECT_INTERNAL,
+            contentEN);
+
+        try {
+            saveMappings(session);
+            
+            // de content mapping
+            final HttpServletRequest requestDE = new FakeSlingHttpServletRequest(
+                null, hostDE, -1, rootPath);
+            final Resource resDE0 = resResolver.resolve(requestDE,
+                "/playground.html");
+            assertNotNull(resDE0);
+            assertEquals(contentDE + "/playground.html", resDE0.getPath());
+
+            final Resource resDE1 = resResolver.resolve(requestDE,
+                "/playground/index.html");
+            assertNotNull(resDE1);
+            assertEquals(contentDE + "/playground/index.html", resDE1.getPath());
+
+            final String mappedDE00 = resResolver.map(resDE0.getPath());
+            assertEquals("http://" + hostDE + "/playground.html", mappedDE00);
+            final String mappedDE01 = resResolver.map(requestDE, resDE0.getPath());
+            assertEquals("/playground.html", mappedDE01);
+
+            final String mappedDE10 = resResolver.map(resDE1.getPath());
+            assertEquals("http://" + hostDE + "/playground/index.html", mappedDE10);
+            final String mappedDE11 = resResolver.map(requestDE, resDE1.getPath());
+            assertEquals("/playground/index.html", mappedDE11);
+
+            // en content mapping
+
+            final HttpServletRequest requestEN = new FakeSlingHttpServletRequest(
+                null, hostEN, -1, rootPath);
+            final Resource resEN0 = resResolver.resolve(requestEN,
+                "/playground.html");
+            assertNotNull(resEN0);
+            assertEquals(contentEN + "/playground.html", resEN0.getPath());
+
+            final Resource resEN1 = resResolver.resolve(requestEN,
+                "/playground/index.html");
+            assertNotNull(resEN1);
+            assertEquals(contentEN + "/playground/index.html", resEN1.getPath());
+
+            final String mappedEN00 = resResolver.map(resEN0.getPath());
+            assertEquals("http://" + hostEN + "/playground.html", mappedEN00);
+            final String mappedEN01 = resResolver.map(requestEN, resEN0.getPath());
+            assertEquals("/playground.html", mappedEN01);
+
+            final String mappedEN10 = resResolver.map(resEN1.getPath());
+            assertEquals("http://" + hostEN + "/playground/index.html", mappedEN10);
+            final String mappedEN11 = resResolver.map(requestEN, resEN1.getPath());
+            assertEquals("/playground/index.html", mappedEN11);
+        } finally {
+            virtualhost80a.remove();
+            virtualhost80.remove();
+            session.save();
+        }
+    }
+
+    @Test public void testResolveVirtualHostHttp80MultipleRoot() throws Exception {
+
+        final String de = "de";
+        final String en = "en";
+        final String fr = "fr";
+        final String hostDE = de + ".host.com";
+        final String hostEN = en + ".host.com";
+        final String hostFR = fr + ".host.com";
+
+        Node virtualhost80a = mapRoot.getNode("map/http").addNode(
+            hostDE + ".80", "sling:Mapping");
+        virtualhost80a.setProperty(PROP_REDIRECT_INTERNAL,
+            "/");
+        Node virtualhost80 = mapRoot.getNode("map/http").addNode(hostEN + ".80",
+            "sling:Mapping");
+        virtualhost80.setProperty(PROP_REDIRECT_INTERNAL,
+            "/");
+
+        try {
+            saveMappings(session);
+            
+            // de content mapping
+            final HttpServletRequest requestDE = new FakeSlingHttpServletRequest(
+                null, hostDE, -1, rootPath);
+            final Resource resDE0 = resResolver.resolve(requestDE,
+                "/playground.html");
+            assertNotNull(resDE0);
+            assertEquals("/playground.html", resDE0.getPath());
+
+            final Resource resDE1 = resResolver.resolve(requestDE,
+                "/playground/index.html");
+            assertNotNull(resDE1);
+            assertEquals("/playground/index.html", resDE1.getPath());
+
+            final String mappedDE00 = resResolver.map(resDE0.getPath());
+            assertEquals("http://" + hostDE + "/playground.html", mappedDE00);
+            final String mappedDE01 = resResolver.map(requestDE, resDE0.getPath());
+            assertEquals("/playground.html", mappedDE01);
+
+            final String mappedDE10 = resResolver.map(resDE1.getPath());
+            assertEquals("http://" + hostDE + "/playground/index.html", mappedDE10);
+            final String mappedDE11 = resResolver.map(requestDE, resDE1.getPath());
+            assertEquals("/playground/index.html", mappedDE11);
+
+            // en content mapping
+
+            final HttpServletRequest requestEN = new FakeSlingHttpServletRequest(
+                null, hostEN, -1, rootPath);
+            final Resource resEN0 = resResolver.resolve(requestEN,
+                "/playground.html");
+            assertNotNull(resEN0);
+            assertEquals("/playground.html", resEN0.getPath());
+
+            final Resource resEN1 = resResolver.resolve(requestEN,
+                "/playground/index.html");
+            assertNotNull(resEN1);
+            assertEquals("/playground/index.html", resEN1.getPath());
+
+            // here we get back the hostDE, since this is the first configured
+            // and we have no request information to map the correct of the
+            // duplicate entries !
+            final String mappedEN00 = resResolver.map(resEN0.getPath());
+            assertEquals("http://" + hostDE + "/playground.html", mappedEN00);
+
+            // here we expect the path without scheme/host/port since we have
+            // the request and can select the right mapping
+            final String mappedEN01 = resResolver.map(requestEN, resEN0.getPath());
+            assertEquals("/playground.html", mappedEN01);
+
+            // here we get back the hostDE, since this is the first configured
+            // and we have no request information to map the correct of the
+            // duplicate entries !
+            final String mappedEN10 = resResolver.map(resEN1.getPath());
+            assertEquals("http://" + hostDE + "/playground/index.html", mappedEN10);
+
+            // here we expect the path without scheme/host/port since we have
+            // the request and can select the right mapping
+            final String mappedEN11 = resResolver.map(requestEN, resEN1.getPath());
+            assertEquals("/playground/index.html", mappedEN11);
+
+            final HttpServletRequest requestFR = new FakeSlingHttpServletRequest(
+                null, hostFR, -1, rootPath);
+            final Resource resFR1 = resResolver.resolve(requestFR,
+                "/playground/index.html");
+            assertNotNull(resFR1);
+            assertEquals("/playground/index.html", resFR1.getPath());
+
+            // here we get back the hostDE, since this is the first configured
+            // and we have no request information to map the correct of the
+            // duplicate entries !
+            final String mappedFR10 = resResolver.map(resFR1.getPath());
+            assertEquals("http://" + hostDE + "/playground/index.html", mappedFR10);
+
+            // here we get back the hostDE, since this is the first configured
+            // and we have request information which does not map any of the
+            // configured duplicate entries !
+            final String mappedFR11 = resResolver.map(requestFR, resFR1.getPath());
+            assertEquals("http://" + hostDE + "/playground/index.html", mappedFR11);
+        } finally {
+            virtualhost80a.remove();
+            virtualhost80.remove();
+            session.save();
+        }
+    }
+
+    @Test public void testResolveVirtualHostHttp8080() throws Exception {
+        HttpServletRequest request = new FakeSlingHttpServletRequest(null,
+            "virtual.host.com", 8080, rootPath);
+        Node virtualhost80 = mapRoot.getNode("map/http").addNode(
+            "virtual.host.com.8080", "sling:Mapping");
+        virtualhost80.setProperty(PROP_REDIRECT_INTERNAL,
+            "/content/virtual");
+
+        try {
+            saveMappings(session);
+            final Resource res0 = resResolver.resolve(request, "/playground.html");
+            assertNotNull(res0);
+            assertEquals("/content/virtual/playground.html", res0.getPath());
+
+            final Resource res1 = resResolver.resolve(request,
+                "/playground/en.html");
+            assertNotNull(res1);
+            assertEquals("/content/virtual/playground/en.html", res1.getPath());
+
+            final String mapped00 = resResolver.map(res0.getPath());
+            assertEquals("http://virtual.host.com:8080/playground.html", mapped00);
+            final String mapped01 = resResolver.map(request, res0.getPath());
+            assertEquals("/playground.html", mapped01);
+
+            final String mapped10 = resResolver.map(res1.getPath());
+            assertEquals("http://virtual.host.com:8080/playground/en.html",
+                mapped10);
+            final String mapped11 = resResolver.map(request, res1.getPath());
+            assertEquals("/playground/en.html", mapped11);
+        } finally {
+            virtualhost80.remove();
+            session.save();
+        }
+    }
+
+    @Test public void testResolveVirtualHostHttp8080Root() throws Exception {
+        HttpServletRequest request = new FakeSlingHttpServletRequest(null,
+            "virtual.host.com", 8080, rootPath);
+        Node virtualhost80 = mapRoot.getNode("map/http").addNode(
+            "virtual.host.com.8080", "sling:Mapping");
+        virtualhost80.setProperty(PROP_REDIRECT_INTERNAL,
+            "/");
+
+        try {
+            saveMappings(session);
+            final Resource res0 = resResolver.resolve(request, "/playground.html");
+            assertNotNull(res0);
+            assertEquals("/playground.html", res0.getPath());
+
+            final Resource res1 = resResolver.resolve(request,
+                "/playground/en.html");
+            assertNotNull(res1);
+            assertEquals("/playground/en.html", res1.getPath());
+
+            final String mapped00 = resResolver.map(res0.getPath());
+            assertEquals("http://virtual.host.com:8080/playground.html", mapped00);
+            final String mapped01 = resResolver.map(request, res0.getPath());
+            assertEquals("/playground.html", mapped01);
+
+            final String mapped10 = resResolver.map(res1.getPath());
+            assertEquals("http://virtual.host.com:8080/playground/en.html",
+                mapped10);
+            final String mapped11 = resResolver.map(request, res1.getPath());
+            assertEquals("/playground/en.html", mapped11);
+        } finally {
+            virtualhost80.remove();
+            session.save();
+        }
+    }
+
+    @Test public void testResolveVirtualHostHttps443() throws Exception {
+        HttpServletRequest request = new FakeSlingHttpServletRequest("https",
+            "virtual.host.com", -1, rootPath);
+        Node virtualhost443 = mapRoot.getNode("map/https").addNode(
+            "virtual.host.com.443", "sling:Mapping");
+        virtualhost443.setProperty(PROP_REDIRECT_INTERNAL,
+            "/content/virtual");
+
+        try {
+            saveMappings(session);
+            final Resource res0 = resResolver.resolve(request, "/playground.html");
+            assertNotNull(res0);
+            assertEquals("/content/virtual/playground.html", res0.getPath());
+
+            final Resource res1 = resResolver.resolve(request,
+                "/playground/en.html");
+            assertNotNull(res1);
+            assertEquals("/content/virtual/playground/en.html", res1.getPath());
+
+            final String mapped00 = resResolver.map(res0.getPath());
+            assertEquals("https://virtual.host.com/playground.html", mapped00);
+            final String mapped01 = resResolver.map(request, res0.getPath());
+            assertEquals("/playground.html", mapped01);
+
+            final String mapped10 = resResolver.map(res1.getPath());
+            assertEquals("https://virtual.host.com/playground/en.html", mapped10);
+            final String mapped11 = resResolver.map(request, res1.getPath());
+            assertEquals("/playground/en.html", mapped11);
+        } finally {
+            virtualhost443.remove();
+            session.save();
+        }
+    }
+
+    @Test public void testResolveVirtualHostHttps4443() throws Exception {
+        HttpServletRequest request = new FakeSlingHttpServletRequest("https",
+            "virtual.host.com", 4443, rootPath);
+        Node virtualhost4443 = mapRoot.getNode("map/https").addNode(
+            "virtual.host.com.4443", "sling:Mapping");
+        virtualhost4443.setProperty(PROP_REDIRECT_INTERNAL,
+            "/content/virtual");
+        
+        try {
+            saveMappings(session);
+            final Resource res0 = resResolver.resolve(request, "/playground.html");
+            assertNotNull(res0);
+            assertEquals("/content/virtual/playground.html", res0.getPath());
+
+            final Resource res1 = resResolver.resolve(request,
+                "/playground/en.html");
+            assertNotNull(res1);
+            assertEquals("/content/virtual/playground/en.html", res1.getPath());
+
+            final String mapped00 = resResolver.map(res0.getPath());
+            assertEquals("https://virtual.host.com:4443/playground.html", mapped00);
+            final String mapped01 = resResolver.map(request, res0.getPath());
+            assertEquals("/playground.html", mapped01);
+
+            final String mapped10 = resResolver.map(res1.getPath());
+            assertEquals("https://virtual.host.com:4443/playground/en.html",
+                mapped10);
+            final String mapped11 = resResolver.map(request, res1.getPath());
+            assertEquals("/playground/en.html", mapped11);
+        } finally {
+            virtualhost4443.remove();
+            session.save();
+        }
+    }
+
+    @Test public void testResolveVirtualHostHttpVsHttps() throws Exception {
+
+        final String host0 = "www.host.com";
+        final String host1 = "secure.host.com";
+        final String content = "/content/page";
+
+        Node virtualhost80 = mapRoot.getNode("map/http").addNode(host0 + ".80",
+            "sling:Mapping");
+        virtualhost80.setProperty(PROP_REDIRECT_INTERNAL,
+            content);
+        Node virtualhost443 = mapRoot.getNode("map/https").addNode(
+            host0 + ".443", "sling:Mapping");
+        virtualhost443.setProperty(PROP_REDIRECT_INTERNAL,
+            content);
+
+        // HTTP request
+        try {
+            saveMappings(session);
+            final HttpServletRequest requestHttp0 = new FakeSlingHttpServletRequest(
+                null, host0, -1, rootPath);
+            final Resource resHttp0 = resResolver.resolve(requestHttp0, "/playground.html");
+            assertNotNull(resHttp0);
+            assertEquals(content + "/playground.html", resHttp0.getPath());
+
+            final Resource resHttp1 = resResolver.resolve(requestHttp0,
+            "/playground/index.html");
+            assertNotNull(resHttp1);
+            assertEquals(content + "/playground/index.html", resHttp1.getPath());
+
+            // HTTPS request
+            final HttpServletRequest requestHttps0 = new FakeSlingHttpServletRequest(
+                "https", host0, -1, rootPath);
+            final Resource resHttps0 = resResolver.resolve(requestHttps0, "/playground.html");
+            assertNotNull(resHttps0);
+            assertEquals(content + "/playground.html", resHttps0.getPath());
+
+            final Resource resHttps1 = resResolver.resolve(requestHttps0,
+                "/playground/index.html");
+            assertNotNull(resHttps1);
+            assertEquals(content + "/playground/index.html", resHttps1.getPath());
+
+            // HTTP Mapping
+
+            final String mappedHttp00 = resResolver.map(resHttp0.getPath());
+            assertEquals("http://" + host0 + "/playground.html", mappedHttp00);
+            final String mappedHttp01 = resResolver.map(requestHttp0, resHttp0.getPath());
+            assertEquals("/playground.html", mappedHttp01);
+
+            final String mappedHttp10 = resResolver.map(resHttp1.getPath());
+            assertEquals("http://" + host0 + "/playground/index.html", mappedHttp10);
+            final String mappedHttp11 = resResolver.map(requestHttp0, resHttp1.getPath());
+            assertEquals("/playground/index.html", mappedHttp11);
+
+            // HTTPS Mapping
+
+            final HttpServletRequest requestHttp1 = new FakeSlingHttpServletRequest(
+                null, host1, -1, rootPath);
+            final HttpServletRequest requestHttps1 = new FakeSlingHttpServletRequest(
+                "https", host1, -1, rootPath);
+
+            final String mappedHttps00 = resResolver.map(resHttps0.getPath());
+            assertEquals("http://" + host0 + "/playground.html", mappedHttps00);
+            final String mappedHttps01 = resResolver.map(requestHttps0, resHttps0.getPath());
+            assertEquals("/playground.html", mappedHttps01);
+            final String mappedHttps02 = resResolver.map(requestHttp1, resHttps0.getPath());
+            assertEquals("http://" + host0 + "/playground.html", mappedHttps02);
+            final String mappedHttps03 = resResolver.map(requestHttps1, resHttps0.getPath());
+            assertEquals("https://" + host0 + "/playground.html", mappedHttps03);
+
+            final String mappedHttps10 = resResolver.map(resHttps1.getPath());
+            assertEquals("http://" + host0 + "/playground/index.html", mappedHttps10);
+            final String mappedHttps11 = resResolver.map(requestHttps0, resHttps1.getPath());
+            assertEquals("/playground/index.html", mappedHttps11);
+            final String mappedHttps12 = resResolver.map(requestHttp1, resHttps1.getPath());
+            assertEquals("http://" + host0 + "/playground/index.html", mappedHttps12);
+            final String mappedHttps13 = resResolver.map(requestHttps1, resHttps1.getPath());
+            assertEquals("https://" + host0 + "/playground/index.html", mappedHttps13);
+        } finally {
+            virtualhost80.remove();
+            virtualhost443.remove();
+            session.save();
+        }
+    }
+
+    @Test public void testResolveResourceAlias() throws Exception {
+        // define an alias for the rootPath
+        String alias = "testAlias";
+        rootNode.setProperty("sling:alias", alias);
+
+        try {
+            saveMappings(session);
+            String path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                + "/" + alias + ".print.html");
+
+            HttpServletRequest request = new FakeSlingHttpServletRequest(path);
+            Resource res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertEquals(rootPath, res.getPath());
+            assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+            assertEquals(".print.html",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+            path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath) + "/"
+                + alias + ".print.html/suffix.pdf");
+
+            request = new FakeSlingHttpServletRequest(path);
+            res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertEquals(rootPath, res.getPath());
+            assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+            assertEquals(".print.html/suffix.pdf",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+        } finally {
+            rootNode.getProperty("sling:alias").remove();
+            session.save();
+        }
+    }
+
+    @Test public void testResolveResourceAliasWithUpdate() throws Exception {
+        // define an alias for the rootPath
+        String [] alias = {"testAlias","testAliasToUpdate"};
+        rootNode.setProperty("sling:alias", alias);
+
+        try {
+            saveMappings(session);
+            String path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                    + "/" + alias[1] + ".print.html");
+
+            HttpServletRequest request = new FakeSlingHttpServletRequest(path);
+            Resource res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertEquals(rootPath, res.getPath());
+            assertEquals(rootNode.getPrimaryNodeType().getName(),
+                    res.getResourceType());
+
+            assertEquals(".print.html",
+                    res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+            path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath) + "/"
+                    + alias[1] + ".print.html/suffix.pdf");
+
+            request = new FakeSlingHttpServletRequest(path);
+            res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertEquals(rootPath, res.getPath());
+            assertEquals(rootNode.getPrimaryNodeType().getName(),
+                    res.getResourceType());
+
+            assertEquals(".print.html/suffix.pdf",
+                    res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+            //update alias  
+            String [] aliasUpdated =  {"testAlias","testAliasUpdated"};
+            rootNode.setProperty("sling:alias", aliasUpdated);
+            saveMappings(session);
+
+            path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                    + "/" + aliasUpdated[1] + ".print.html");
+
+            request = new FakeSlingHttpServletRequest(path);
+            res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertEquals(rootPath, res.getPath());
+            assertEquals(rootNode.getPrimaryNodeType().getName(),
+                    res.getResourceType());
+
+            assertEquals(".print.html",
+                    res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+            path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath) + "/"
+                    + aliasUpdated[1] + ".print.html/suffix.pdf");
+
+            request = new FakeSlingHttpServletRequest(path);
+            res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertEquals(rootPath, res.getPath());
+            assertEquals(rootNode.getPrimaryNodeType().getName(),
+                    res.getResourceType());
+
+            assertEquals(".print.html/suffix.pdf",
+                    res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+        } finally {
+            rootNode.getProperty("sling:alias").remove();
+            session.save();
+        }
+    }
+    
+    @Test public void testResolveRemovedResourceAlias() throws Exception {
+        // define an alias for the rootPath
+        String alias = "testAlias";
+        rootNode.setProperty("sling:alias", alias);
+
+        saveMappings(session);
+        String path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                + "/" + alias + ".print.html");
+
+        HttpServletRequest request = new FakeSlingHttpServletRequest(path);
+        Resource res = resResolver.resolve(request, path);
+        assertNotNull(res);
+        assertEquals(rootPath, res.getPath());
+        assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+        assertEquals(".print.html",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+        assertNotNull(res.adaptTo(Node.class));
+        assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+        path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath) + "/"
+                + alias + ".print.html/suffix.pdf");
+
+        request = new FakeSlingHttpServletRequest(path);
+        res = resResolver.resolve(request, path);
+        assertNotNull(res);
+        assertEquals(rootPath, res.getPath());
+        assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+        assertEquals(".print.html/suffix.pdf",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+        assertNotNull(res.adaptTo(Node.class));
+        assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+        //remove alias property
+        rootNode.getProperty("sling:alias").remove();
+        saveMappings(session);
+
+        path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                + "/" + alias + ".print.html");
+
+        request = new FakeSlingHttpServletRequest(path);
+        res = resResolver.resolve(request, path);
+
+        assertNotNull(res);
+        assertTrue(res instanceof NonExistingResource);
+        assertEquals("/"+alias+".print.html", res.getPath());
+        
+        //create new child with alias
+        String childNodeName = "rootChildAlias";
+        Node childNode = maybeCreateNode(rootNode, childNodeName, "nt:unstructured");
+        childNode.setProperty("sling:alias", "childAlias");
+        saveMappings(session);
+
+        path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)+ "/"+ rootPath
+                + "/childAlias.print.html");
+
+        request = new FakeSlingHttpServletRequest(path);
+        res = resResolver.resolve(request, path);
+        assertNotNull(res);
+        assertEquals(rootPath+"/"+childNodeName, res.getPath());
+        assertEquals(childNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+        assertEquals(".print.html",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+        assertNotNull(res.adaptTo(Node.class));
+        assertTrue(childNode.isSame(res.adaptTo(Node.class)));
+
+        path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)+ "/"+ rootPath + "/childAlias" +
+                ".print.html/suffix.pdf");
+
+        request = new FakeSlingHttpServletRequest(path);
+        res = resResolver.resolve(request, path);
+        assertNotNull(res);
+        assertEquals(rootPath+"/"+childNodeName, res.getPath());
+        assertEquals(childNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+        assertEquals(".print.html/suffix.pdf",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+        assertNotNull(res.adaptTo(Node.class));
+        assertTrue(childNode.isSame(res.adaptTo(Node.class)));
+
+        
+        //remove the child node with the alias
+        childNode.remove();
+        saveMappings(session);
+        
+        path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)+ "/"+ rootPath + "/childAlias" +
+                ".print.html");
+
+        request = new FakeSlingHttpServletRequest(path);
+        res = resResolver.resolve(request, path);
+        
+        assertNotNull(res);
+        assertTrue(res instanceof NonExistingResource);
+        assertEquals (rootPath + "/childAlias.print.html", res.getPath());
+    }
+    
+    @Test public void testResolveResourceAliasJcrContent() throws Exception {
+        // define an alias for the rootPath in the jcr:content child node
+        String alias = "testAlias";
+        Node content = rootNode.addNode("jcr:content", "nt:unstructured");
+        content.setProperty("sling:alias", alias);
+
+        try {
+            saveMappings(session);
+            String path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                + "/" + alias + ".print.html");
+
+            HttpServletRequest request = new FakeSlingHttpServletRequest(path);
+            Resource res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertEquals(rootPath, res.getPath());
+            assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+            assertEquals(".print.html",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+            path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath) + "/"
+                + alias + ".print.html/suffix.pdf");
+
+            request = new FakeSlingHttpServletRequest(path);
+            res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertEquals(rootPath, res.getPath());
+            assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+            assertEquals(".print.html/suffix.pdf",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+            path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                    + "/" + alias + "/" + alias + ".print.html");
+            res = resResolver.resolve(request, path);
+            assertEquals("GET request resolution does not go up the path",
+                    Resource.RESOURCE_TYPE_NON_EXISTING, res.getResourceType());
+
+            Node child = rootNode.addNode("child", "nt:unstructured");
+            child.setProperty("sling:alias", alias);
+
+            try {
+                saveMappings(session);
+                res = resResolver.resolve(request, path);
+                assertEquals(child.getPath(), res.getPath());
+            } finally {
+                child.remove();
+                session.save();
+            }
+        } finally {
+            content.remove();
+            session.save();
+        }
+
+    }
+
+    @Test public void testResolveResourceAliasJcrContentWithUpdate() throws Exception {
+        // define an alias for the rootPath in the jcr:content child node
+        String [] alias = {"testAlias","testAliasToUpdate"};
+        Node content = rootNode.addNode("jcr:content", "nt:unstructured");
+        content.setProperty("sling:alias", alias);
+
+        try {
+            saveMappings(session);
+            String path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                + "/" + alias[1] + ".print.html");
+
+            HttpServletRequest request = new FakeSlingHttpServletRequest(path);
+            Resource res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertEquals(rootPath, res.getPath());
+            assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+            assertEquals(".print.html",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+            path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath) + "/"
+                + alias[1] + ".print.html/suffix.pdf");
+
+            request = new FakeSlingHttpServletRequest(path);
+            res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertEquals(rootPath, res.getPath());
+            assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+            assertEquals(".print.html/suffix.pdf",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+            //update alias  
+            String [] aliasUpdated =  {"testAlias","testAliasUpdated"};
+            content.setProperty("sling:alias", aliasUpdated);
+            saveMappings(session);
+
+            path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                    + "/" + aliasUpdated[1] + ".print.html");
+
+            request = new FakeSlingHttpServletRequest(path);
+            res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertEquals(rootPath, res.getPath());
+            assertEquals(rootNode.getPrimaryNodeType().getName(),
+                    res.getResourceType());
+
+            assertEquals(".print.html",
+                    res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+            path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath) + "/"
+                    + aliasUpdated[1] + ".print.html/suffix.pdf");
+
+            request = new FakeSlingHttpServletRequest(path);
+            res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertEquals(rootPath, res.getPath());
+            assertEquals(rootNode.getPrimaryNodeType().getName(),
+                    res.getResourceType());
+
+            assertEquals(".print.html/suffix.pdf",
+                    res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+        } finally {
+            content.remove();
+            session.save();
+        }
+
+    }
+    
+    @Test public void testResolveRemovedesourceAliasJcrContent() throws Exception {
+        // define an alias for the rootPath in the jcr:content child node
+        String alias = "testAlias";
+        Node content = rootNode.addNode("jcr:content", "nt:unstructured");
+        content.setProperty("sling:alias", alias);
+
+        try {
+            saveMappings(session);
+            String path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                + "/" + alias + ".print.html");
+
+            HttpServletRequest request = new FakeSlingHttpServletRequest(path);
+            Resource res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertEquals(rootPath, res.getPath());
+            assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+            assertEquals(".print.html",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+            path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath) + "/"
+                + alias + ".print.html/suffix.pdf");
+
+            request = new FakeSlingHttpServletRequest(path);
+            res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertEquals(rootPath, res.getPath());
+            assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+            assertEquals(".print.html/suffix.pdf",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+            path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                    + "/" + alias + "/" + alias + ".print.html");
+            res = resResolver.resolve(request, path);
+            assertEquals("GET request resolution does not go up the path",
+                    Resource.RESOURCE_TYPE_NON_EXISTING, res.getResourceType());
+
+            //remove alias property
+            content.getProperty("sling:alias").remove();
+            saveMappings(session);
+
+            path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                    + "/" + alias + ".print.html");
+            request = new FakeSlingHttpServletRequest(path);
+            res = resResolver.resolve(request, path);
+            
+            assertNotNull(res);
+            assertTrue(res instanceof NonExistingResource);
+            assertEquals("/"+alias+".print.html", res.getPath());  
+
+        } finally {
+            content.remove();
+            session.save();
+        }
+
+    }
+    
+    
+    @Test public void testResolveVanityPath() throws Exception {
+        String path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                + "/" + vanity[0] + ".print.html");
+
+        HttpServletRequest request = new FakeSlingHttpServletRequest(path);
+        Resource res = resResolver.resolve(request, path);
+        assertNotNull(res);
+        assertEquals(rootPath, res.getPath());
+        assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+        assertEquals(".print.html",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+        assertNotNull(res.adaptTo(Node.class));
+        assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+        path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath) + "/"
+                + vanity[0] + ".print.html/suffix.pdf");
+
+        request = new FakeSlingHttpServletRequest(path);
+        res = resResolver.resolve(request, path);
+        assertNotNull(res);
+        assertEquals(rootPath, res.getPath());
+        assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+        assertEquals(".print.html/suffix.pdf",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+        assertNotNull(res.adaptTo(Node.class));
+        assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+        
+        path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                + "/" + vanity[1] + ".print.html");
+
+        request = new FakeSlingHttpServletRequest(path);
+        res = resResolver.resolve(request, path);
+        assertNotNull(res);
+        assertEquals(rootPath, res.getPath());
+        assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+        assertEquals(".print.html",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+        assertNotNull(res.adaptTo(Node.class));
+        assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+        path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath) + "/"
+                + vanity[1] + ".print.html/suffix.pdf");
+
+        request = new FakeSlingHttpServletRequest(path);
+        res = resResolver.resolve(request, path);
+        assertNotNull(res);
+        assertEquals(rootPath, res.getPath());
+        assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+        assertEquals(".print.html/suffix.pdf",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+        assertNotNull(res.adaptTo(Node.class));
+        assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+    }
+    
+    @Test public void testResolveVanityPathWithUpdate() throws Exception {
+        String path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                + "/" + vanity[2] + ".print.html");
+
+        HttpServletRequest request = new FakeSlingHttpServletRequest(path);
+        Resource res = resResolver.resolve(request, path);
+        assertNotNull(res);
+        assertEquals(rootPath, res.getPath());
+        assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+        assertEquals(".print.html",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+        assertNotNull(res.adaptTo(Node.class));
+        assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+        path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath) + "/"
+                + vanity[2] + ".print.html/suffix.pdf");
+
+        request = new FakeSlingHttpServletRequest(path);
+        res = resResolver.resolve(request, path);
+        assertNotNull(res);
+        assertEquals(rootPath, res.getPath());
+        assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+        assertEquals(".print.html/suffix.pdf",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+        assertNotNull(res.adaptTo(Node.class));
+        assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+        
+        //update vanityPath
+        String [] vanityPathUpdated = new String[] {"testVanity","testV", "testVanityUpdated"};
+        rootNode.setProperty("sling:vanityPath", vanityPathUpdated);
+        saveMappings(session);
+        
+        path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                + "/" + vanityPathUpdated[2] + ".print.html");
+
+        request = new FakeSlingHttpServletRequest(path);
+        res = resResolver.resolve(request, path);
+        assertNotNull(res);
+        assertEquals(rootPath, res.getPath());
+        assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+        assertEquals(".print.html",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+        assertNotNull(res.adaptTo(Node.class));
+        assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+
+        path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath) + "/"
+                + vanityPathUpdated[2] + ".print.html/suffix.pdf");
+
+        request = new FakeSlingHttpServletRequest(path);
+        res = resResolver.resolve(request, path);
+        assertNotNull(res);
+        assertEquals(rootPath, res.getPath());
+        assertEquals(rootNode.getPrimaryNodeType().getName(),
+                res.getResourceType());
+
+        assertEquals(".print.html/suffix.pdf",
+                res.getResourceMetadata().getResolutionPathInfo());
+
+        assertNotNull(res.adaptTo(Node.class));
+        assertTrue(rootNode.isSame(res.adaptTo(Node.class)));
+        
+        
+        path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                + "/" + vanity[2] + ".print.html");
+
+        request = new FakeSlingHttpServletRequest(path);
+        res = resResolver.resolve(request, path);
+        assertNotNull(res);
+        assertTrue(res instanceof NonExistingResource);
+        assertEquals("/"+vanity[2]+".print.html", res.getPath());
+    }
+       
+    @Ignore //see SLING-3558
+    @Test public void testResolveRemovedMixinVanityPath() throws Exception {   
+        Node childNode = null;
+        
+        try  {
+            //create new child with vanity path without mixin
+            childNode = maybeCreateNode(rootNode, "rootChild", "nt:unstructured");
+            childNode.setProperty("sling:vanityPath", "childVanity");
+            saveMappings(session);
+            
+            String path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                    + "/childVanity.print.html");
+            HttpServletRequest request = new FakeSlingHttpServletRequest(path);
+            Resource res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertTrue(res instanceof NonExistingResource);
+            assertEquals("/childVanity.print.html", res.getPath());
+            
+            //add mixin
+            childNode.addMixin("sling:VanityPath");
+            saveMappings(session);
+            
+            path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                    + "/childVanity.print.html");
+
+            request = new FakeSlingHttpServletRequest(path);
+            res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertEquals(childNode.getPath(), res.getPath());
+            assertEquals(childNode.getPrimaryNodeType().getName(),
+                    res.getResourceType());
+
+            assertEquals(".print.html",
+                    res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(childNode.isSame(res.adaptTo(Node.class)));
+            
+            //remove mixin  
+            childNode.removeMixin("sling:VanityPath");
+            saveMappings(session);
+
+            path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                    + "/childVanity.print.html");
+            request = new FakeSlingHttpServletRequest(path);
+            res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertTrue(res instanceof NonExistingResource);
+            assertEquals("/childVanity.print.html", res.getPath());
+        } finally {
+            if (childNode != null){
+                childNode.remove();
+                saveMappings(session);
+            }
+        }
+    }
+    
+    @Test public void testResolveVanityPathWithVanityOrder() throws Exception {    
+        Node childNode = null;
+        Node childNode2 = null;
+        
+        try  {
+            //create new child with vanity path
+            childNode = maybeCreateNode(rootNode, "rootChild", "nt:unstructured");
+            childNode.setProperty("sling:vanityPath", "childVanity");
+            childNode.addMixin("sling:VanityPath");
+            saveMappings(session);
+                       
+            String path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                    + "/childVanity.print.html");
+            HttpServletRequest request = new FakeSlingHttpServletRequest(path);
+            Resource res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertEquals(childNode.getPath(), res.getPath());
+            assertEquals(childNode.getPrimaryNodeType().getName(),
+                    res.getResourceType());
+
+            assertEquals(".print.html",
+                    res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(childNode.isSame(res.adaptTo(Node.class)));
+            
+            //create another child with the same vanity path
+            childNode2 = maybeCreateNode(rootNode, "rootChild2", "nt:unstructured");
+            childNode2.setProperty("sling:vanityPath", "childVanity");
+            childNode2.addMixin("sling:VanityPath");
+            saveMappings(session);
+ 
+            assertNotNull(res);
+            assertEquals(childNode.getPath(), res.getPath());
+            assertEquals(childNode.getPrimaryNodeType().getName(),
+                    res.getResourceType());
+
+            assertEquals(".print.html",
+                    res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(childNode.isSame(res.adaptTo(Node.class)));
+            
+            //add vanityOrder to childNode2
+            childNode2.setProperty("sling:vanityOrder", 100);
+            saveMappings(session);
+            
+            path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                    + "/childVanity.print.html");
+            request = new FakeSlingHttpServletRequest(path);
+            res = resResolver.resolve(request, path);
+            
+            assertNotNull(res);
+            assertEquals(childNode2.getPath(), res.getPath());
+            assertEquals(childNode2.getPrimaryNodeType().getName(),
+                    res.getResourceType());
+
+            assertEquals(".print.html",
+                    res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(childNode2.isSame(res.adaptTo(Node.class)));
+            
+            //add vanityOrder to childNode higher than childNode2
+            childNode.setProperty("sling:vanityOrder", 1000);
+            saveMappings(session);
+            
+            path = ResourceUtil.normalize(ResourceUtil.getParent(rootPath)
+                    + "/childVanity.print.html");
+            request = new FakeSlingHttpServletRequest(path);
+            res = resResolver.resolve(request, path);
+            assertNotNull(res);
+            assertEquals(childNode.getPath(), res.getPath());
+            assertEquals(childNode.getPrimaryNodeType().getName(),
+                    res.getResourceType());
+
+            assertEquals(".print.html",
+                    res.getResourceMetadata().getResolutionPathInfo());
+
+            assertNotNull(res.adaptTo(Node.class));
+            assertTrue(childNode.isSame(res.adaptTo(Node.class)));
+            
+        } finally {
+            if (childNode != null){
+                childNode.remove();                 
+            }
+            if (childNode2 != null){
+                childNode2.remove();                 
+            }
+            session.save();
+        }            
+    }
+
+    
+    @Test public void testGetDoesNotGoUp() throws Exception {
+
+        final String path = rootPath + "/nothing";
+
+        {
+            final Resource res = resResolver.resolve(
+                new FakeSlingHttpServletRequest(path, "POST"), path);
+            assertNotNull(res);
+            assertEquals("POST request resolution does not go up the path",
+                Resource.RESOURCE_TYPE_NON_EXISTING, res.getResourceType());
+        }
+
+        {
+            final Resource res = resResolver.resolve(
+                new FakeSlingHttpServletRequest(path, "GET"), path);
+            assertNotNull(res);
+            assertEquals("GET request resolution does not go up the path",
+                Resource.RESOURCE_TYPE_NON_EXISTING, res.getResourceType());
+        }
+    }
+
+    @Test public void testGetRemovesExtensionInResolution() throws Exception {
+        final String path = rootPath + ".whatever";
+        final Resource res = resResolver.resolve(
+            new FakeSlingHttpServletRequest(path, "GET"), path);
+        assertNotNull(res);
+        assertEquals(rootPath, res.getPath());
+        assertEquals(rootNode.getPrimaryNodeType().getName(),
+            res.getResourceType());
+    }
+
+    @Test public void testStarResourcePlain() throws Exception {
+        final String path = rootPath + "/" + System.currentTimeMillis() + "/*";
+        testStarResourceHelper(path, "GET");
+        testStarResourceHelper(path, "POST");
+        testStarResourceHelper(path, "PUT");
+        testStarResourceHelper(path, "DELETE");
+    }
+
+    @Test public void testStarResourceExtension() throws Exception {
+        final String path = rootPath + "/" + System.currentTimeMillis()
+            + "/*.html";
+        testStarResourceHelper(path, "GET");
+        testStarResourceHelper(path, "POST");
+        testStarResourceHelper(path, "PUT");
+        testStarResourceHelper(path, "DELETE");
+    }
+
+    @Test public void testStarResourceSelectorExtension() throws Exception {
+        final String path = rootPath + "/" + System.currentTimeMillis()
+            + "/*.print.a4.html";
+        testStarResourceHelper(path, "GET");
+        testStarResourceHelper(path, "POST");
+        testStarResourceHelper(path, "PUT");
+        testStarResourceHelper(path, "DELETE");
+    }
+
+    @Test public void testSlingFolder() throws Exception {
+
+        // create a folder
+        String folderPath = "folder";
+        Node folder = rootNode.addNode(folderPath, "sling:Folder");
+        rootNode.getSession().save();
+
+        try {
+            // test default child node type
+            Node child = folder.addNode("child0");
+            folder.getSession().save();
+            assertEquals("sling:Folder", child.getPrimaryNodeType().getName());
+
+            // test explicit sling:Folder child
+            child = folder.addNode("child1", "sling:Folder");
+            folder.getSession().save();
+            assertEquals("sling:Folder", child.getPrimaryNodeType().getName());
+
+            // test explicit nt:folder child
+            child = folder.addNode("child2", "nt:folder");
+            folder.getSession().save();
+            assertEquals("nt:folder", child.getPrimaryNodeType().getName());
+
+            // test any child node -- use nt:unstructured here
+            child = folder.addNode("child3", "nt:unstructured");
+            folder.getSession().save();
+            assertEquals("nt:unstructured", child.getPrimaryNodeType().getName());
+        } finally {
+            folder.remove();
+            session.save();
+        }
+    }
+
+    @Test public void testMap() throws Exception {
+        String path = rootNode.getPath();
+        String mapped = resResolver.map(path);
+        assertEquals(path, mapped);
+
+        Node child = rootNode.addNode("child");
+        session.save();
+
+        try {
+            // absolute path, expect rootPath segment to be
+            // cut off the mapped path because we map the rootPath
+            // onto root
+            path = "/child";
+            mapped = resResolver.map(child.getPath());
+            assertEquals(path, mapped);
+        } finally {
+            child.remove();
+            session.save();
+        }
+    }
+
+    @Test public void testMapURLEscaping() throws Exception {
+
+        final String mapHostInternal = "internal.host.com";
+        final String mapRootInternal = "/content/internal";
+
+        Node internalRedirect = mapRoot.getNode("map/http").addNode(
+            mapHostInternal + ".80", "sling:Mapping");
+        internalRedirect.setProperty(
+            PROP_REDIRECT_INTERNAL, mapRootInternal);
+
+        try {
+            saveMappings(session);
+            
+            final String path = "/sample with spaces";
+            final String escapedPath = "/sample%20with%20spaces";
+
+            // ---------------------------------------------------------------------
+            // internal redirect
+
+            // a) test map(String)
+            // => return full URL, escaped
+            String mapped = resResolver.map(mapRootInternal + path);
+            assertEquals("http://" + mapHostInternal + escapedPath, mapped);
+
+            // b) test map(HttpServletRequest, String) with "localhost"
+            // => return full URL, escaped
+            mapped = resResolver.map(new FakeSlingHttpServletRequest(rootPath),
+                mapRootInternal + path);
+            assertEquals("http://" + mapHostInternal + escapedPath, mapped);
+
+            // c) test map(HttpServletRequest, String) with "internal.host.com"
+            // => only return path, escaped, because request host/port matches (cut
+            // off host part)
+            mapped = resResolver.map(new FakeSlingHttpServletRequest(null,
+                mapHostInternal, -1, rootPath), mapRootInternal + path);
+            assertEquals(escapedPath, mapped);
+
+            // ---------------------------------------------------------------------
+            // no mapping config
+            // => return only escaped path
+
+            final String unmappedRoot = "/unmappedRoot";
+
+            // a) test map(String)
+            mapped = resResolver.map(unmappedRoot + path);
+            assertEquals(unmappedRoot + escapedPath, mapped);
+
+            // b) test map(HttpServletRequest, String)
+            mapped = resResolver.map(new FakeSlingHttpServletRequest(rootPath),
+                unmappedRoot + path);
+            assertEquals(unmappedRoot + escapedPath, mapped);
+        } finally {
+            internalRedirect.remove();
+            session.save();
+        }
+
+    }
+
+    @Test public void testMapNamespaceMangling() throws Exception {
+
+        final String mapHost = "virtual.host.com";
+        final String mapRootPath = "/content/virtual";
+        final String contextPath = "/context";
+
+        Node virtualhost80 = mapRoot.getNode("map/http").addNode(
+            mapHost + ".80", "sling:Mapping");
+        virtualhost80.setProperty(PROP_REDIRECT_INTERNAL,
+            mapRootPath);
+
+        try {
+            saveMappings(session);
+            
+            // ---------------------------------------------------------------------
+            // tests expecting paths without context
+
+            final HttpServletRequest virtualRequest = new FakeSlingHttpServletRequest(
+                null, mapHost, -1, rootPath);
+
+            // simple mapping - cut off prefix and add host
+            final String pathv0 = "/sample";
+            final String mappedv0 = resResolver.map(virtualRequest, mapRootPath
+                + pathv0);
+            assertEquals("Expect unmangled path", pathv0, mappedv0);
+
+            // expected name mangling without host prefix
+            final String pathv1 = "/sample/jcr:content";
+            final String mangledv1 = "/sample/_jcr_content";
+            final String mappedv1 = resResolver.map(virtualRequest, mapRootPath
+                + pathv1);
+            assertEquals("Expect mangled path", mangledv1, mappedv1);
+
+            // ---------------------------------------------------------------------
+            // tests expecting paths with context "/context"
+
+            ((FakeSlingHttpServletRequest) virtualRequest).setContextPath(contextPath);
+
+            // simple mapping - cut off prefix and add host
+            final String pathvc0 = "/sample";
+            final String mappedvc0 = resResolver.map(virtualRequest, mapRootPath
+                + pathvc0);
+            assertEquals("Expect unmangled path", contextPath + pathv0, mappedvc0);
+
+            // expected name mangling without host prefix
+            final String pathvc1 = "/sample/jcr:content";
+            final String mangledvc1 = "/sample/_jcr_content";
+            final String mappedvc1 = resResolver.map(virtualRequest, mapRootPath
+                + pathvc1);
+            assertEquals("Expect mangled path", contextPath + mangledvc1, mappedvc1);
+
+            // ---------------------------------------------------------------------

[... 798 lines stripped ...]