You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ra...@apache.org on 2016/11/29 17:42:59 UTC

svn commit: r1771928 - in /sling/trunk/bundles/api: ./ src/main/java/org/apache/sling/api/resource/ src/main/java/org/apache/sling/api/wrappers/ src/test/java/org/apache/sling/api/wrappers/

Author: radu
Date: Tue Nov 29 17:42:59 2016
New Revision: 1771928

URL: http://svn.apache.org/viewvc?rev=1771928&view=rev
Log:
SLING-6336 - Implement a ResourceResolverWrapper

* correctly wrap resources or resource iterators in the RRW
* moved the RRW to the org.apache.sling.api.wrappers sub-package

Added:
    sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/IteratorWrapper.java
    sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/ResourceResolverWrapper.java
    sling/trunk/bundles/api/src/test/java/org/apache/sling/api/wrappers/ResourceResolverWrapperTest.java
Removed:
    sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceResolverWrapper.java
Modified:
    sling/trunk/bundles/api/pom.xml
    sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/package-info.java

Modified: sling/trunk/bundles/api/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/pom.xml?rev=1771928&r1=1771927&r2=1771928&view=diff
==============================================================================
--- sling/trunk/bundles/api/pom.xml (original)
+++ sling/trunk/bundles/api/pom.xml Tue Nov 29 17:42:59 2016
@@ -83,6 +83,12 @@
             <version>2.1.0</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <version>1.10.19</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>

Added: sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/IteratorWrapper.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/IteratorWrapper.java?rev=1771928&view=auto
==============================================================================
--- sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/IteratorWrapper.java (added)
+++ sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/IteratorWrapper.java Tue Nov 29 17:42:59 2016
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * 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.api.wrappers;
+
+import java.util.Iterator;
+
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * Wrapper class for {@code Iterator}s, that forwards all method calls to the wrapped {@code Iterator}.
+ *
+ * @param <T> the type of objects this {@code Iterator} holds
+ */
+@ConsumerType
+public class IteratorWrapper<T> implements Iterator<T> {
+
+    private final Iterator<T> wrapped;
+
+    /**
+     * Creates a wrapping iterator, delegating all method calls to the given {@code wrappedIterator}.
+     *
+     * @param wrappedIterator the wrapped iterator
+     */
+    public IteratorWrapper(Iterator<T> wrappedIterator) {
+        this.wrapped = wrappedIterator;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return wrapped.hasNext();
+    }
+
+    @Override
+    public T next() {
+        return wrapped.next();
+    }
+
+    @Override
+    public void remove() {
+        wrapped.remove();
+    }
+}

Added: sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/ResourceResolverWrapper.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/ResourceResolverWrapper.java?rev=1771928&view=auto
==============================================================================
--- sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/ResourceResolverWrapper.java (added)
+++ sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/ResourceResolverWrapper.java Tue Nov 29 17:42:59 2016
@@ -0,0 +1,403 @@
+/*******************************************************************************
+ * 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.api.wrappers;
+
+import java.util.Iterator;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceWrapper;
+import org.osgi.annotation.versioning.ConsumerType;
+
+/**
+ * The {@code ResourceResolverWrapper} is a wrapper for any {@code ResourceResolver}, delegating all method calls to the wrapped resource
+ * resolver by default. Extensions of this class may overwrite any method to return different values as appropriate.
+ */
+@ConsumerType
+public class ResourceResolverWrapper implements ResourceResolver {
+
+    private ResourceResolver wrapped;
+
+    /**
+     * Creates a new wrapper instance, delegating all calls to the given {@code resolver}.
+     *
+     * @param resolver the wrapped resource resolver
+     */
+    public ResourceResolverWrapper(ResourceResolver resolver) {
+        wrapped = resolver;
+    }
+
+    /**
+     * Wraps and returns the {@code Resource} obtained by calling {@code resolve} on the wrapped resource resolver.
+     *
+     * @param request The http servlet request object providing more hints at
+     *                how to resolve the <code>absPath</code>. This parameter may be
+     *                <code>null</code> in which case the implementation should use
+     *                reasonable defaults.
+     * @param absPath The absolute path to be resolved to a resource. If this
+     *                parameter is <code>null</code>, it is assumed to address the
+     *                root of the resource tree. If the path is relative it is
+     *                assumed relative to the root, that is a slash is prepended to
+     *                the path before resolving it.
+     * @return a wrapped resource obtained through the wrapped resource resolver
+     */
+    @Nonnull
+    @Override
+    public Resource resolve(@Nonnull HttpServletRequest request, @Nonnull String absPath) {
+        return ResourceResolverResourceWrapper.wrap(this, wrapped.resolve(request, absPath));
+    }
+
+    /**
+     * Wraps and returns the {@code Resource} obtained by calling {@code resolve} on the wrapped resource resolver.
+     *
+     * @param absPath The absolute path to be resolved to a resource. If this
+     *                parameter is <code>null</code>, it is assumed to address the
+     *                root of the resource tree. If the path is relative it is
+     *                assumed relative to the root, that is a slash is prepended to
+     *                the path before resolving it.
+     * @return a wrapped resource obtained through the wrapped resource resolver
+     */
+    @Nonnull
+    @Override
+    public Resource resolve(@Nonnull String absPath) {
+        return ResourceResolverResourceWrapper.wrap(this, wrapped.resolve(absPath));
+    }
+
+    /**
+     * Wraps and returns the {@code Resource} obtained by calling {@code resolve} on the wrapped resource resolver.
+     *
+     * @param request The http servlet request object used to resolve the
+     *                resource for. This must not be <code>null</code>.
+     * @return a wrapped resource obtained through the wrapped resource resolver
+     */
+    @Nonnull
+    @Override
+    public Resource resolve(@Nonnull HttpServletRequest request) {
+        return ResourceResolverResourceWrapper.wrap(this, wrapped.resolve(request));
+    }
+
+    @Nonnull
+    @Override
+    public String map(@Nonnull String resourcePath) {
+        return wrapped.map(resourcePath);
+    }
+
+    @Override
+    public String map(@Nonnull HttpServletRequest request, @Nonnull String resourcePath) {
+        return wrapped.map(request, resourcePath);
+    }
+
+    /**
+     * Wraps and returns the {@code Resource} obtained by calling {@code getResource} on the wrapped resource resolver.
+     *
+     * @param path The absolute path to the resource object to be loaded. The
+     *             path may contain relative path specifiers like <code>.</code>
+     *             (current location) and <code>..</code> (parent location),
+     *             which are resolved by this method. If the path is relative,
+     *             that is the first character is not a slash, implementations
+     *             are expected to apply a search path algorithm to resolve the
+     *             relative path to a resource.
+     * @return a wrapped resource obtained through the wrapped resource resolver
+     */
+    @Override
+    public Resource getResource(@Nonnull String path) {
+        return ResourceResolverResourceWrapper.wrap(this, wrapped.getResource(path));
+    }
+
+    /**
+     * Wraps and returns the {@code Resource} obtained by calling {@code getResource} on the wrapped resource resolver.
+     *
+     * @param base The base {@link Resource} against which a relative path
+     *             argument given by <code>path</code> is resolved. This
+     *             parameter may be <code>null</code> if the <code>path</code> is
+     *             known to be absolute.
+     * @param path The path to the resource object to be loaded. If the path is
+     *             relative, i.e. does not start with a slash (<code>/</code>),
+     *             the resource relative to the given <code>base</code> resource
+     *             is returned. The path may contain relative path specifiers
+     *             like <code>.</code> (current location) and <code>..</code>
+     *             (parent location), which are resolved by this method.
+     * @return a wrapped resource obtained through the wrapped resource resolver
+     */
+    @Override
+    public Resource getResource(Resource base, @Nonnull String path) {
+        return ResourceResolverResourceWrapper.wrap(this, wrapped.getResource(base, path));
+    }
+
+    @Nonnull
+    @Override
+    public String[] getSearchPath() {
+        return wrapped.getSearchPath();
+    }
+
+    /**
+     * Wraps and returns the {@code Iterator} obtained by calling {@code listChildren} on the wrapped resource resolver.
+     *
+     * @param parent The {@link Resource Resource} whose children are requested.
+     * @return a wrapped iterator obtained through the wrapped resource resolver
+     */
+    @Nonnull
+    @Override
+    public Iterator<Resource> listChildren(@Nonnull Resource parent) {
+        return new ResourceIteratorWrapper(this, wrapped.listChildren(parent));
+    }
+
+    /**
+     * Wraps and returns the {@code Resource} obtained by calling {@code getParent} on the wrapped resource resolver.
+     *
+     * @param child The {@link Resource Resource} whose parent is requested.
+     * @return a wrapped resource obtained through the wrapped resource resolver
+     */
+    @Override
+    public Resource getParent(@Nonnull Resource child) {
+        return ResourceResolverResourceWrapper.wrap(this, wrapped.getParent(child));
+    }
+
+    /**
+     * Wraps and returns the {@code Iterable} obtained by calling {@code getChildren} on the wrapped resource resolver.
+     *
+     * @param parent The {@link Resource Resource} whose children are requested.
+     * @return a wrapped iterable obtained through the wrapped resource resolver
+     */
+    @Nonnull
+    @Override
+    public Iterable<Resource> getChildren(@Nonnull final Resource parent) {
+        final ResourceResolverWrapper resourceResolverWrapper = this;
+        return new Iterable<Resource>() {
+            @Override
+            public Iterator<Resource> iterator() {
+                return new ResourceIteratorWrapper(resourceResolverWrapper, wrapped.getChildren(parent).iterator());
+            }
+        };
+    }
+
+    /**
+     * Wraps and returns the {@code Iterator} obtained by calling {@code findResources} on the wrapped resource resolver.
+     *
+     * @param query    The query string to use to find the resources.
+     * @param language The language in which the query is formulated. The
+     *                 language should always be specified. However for
+     *                 compatibility with older version, if no language
+     *                 is specified, "xpath" is used.
+     * @return a wrapped iterator obtained through the wrapped resource resolver
+     */
+    @Nonnull
+    @Override
+    public Iterator<Resource> findResources(@Nonnull String query, String language) {
+        return new ResourceIteratorWrapper(this, wrapped.findResources(query, language));
+    }
+
+    @Nonnull
+    @Override
+    public Iterator<Map<String, Object>> queryResources(@Nonnull String query, String language) {
+        return wrapped.queryResources(query, language);
+    }
+
+    @Override
+    public boolean hasChildren(@Nonnull Resource resource) {
+        return wrapped.hasChildren(resource);
+    }
+
+    /**
+     * Wraps and returns the {@code ResourceResolver} obtained by calling {@code clone} on the wrapped resource resolver.
+     *
+     * @param authenticationInfo The map or credential data to overlay the
+     *                           original credential data with for the creation of a new
+     *                           resource resolver. This may be <code>null</code> in which case
+     *                           the same credential data is used as was used to create this
+     *                           instance.
+     * @return a wrapped resource resolver
+     */
+    @Nonnull
+    @Override
+    public ResourceResolver clone(Map<String, Object> authenticationInfo) throws LoginException {
+        ResourceResolver toWrap = wrapped.clone(authenticationInfo);
+        return new ResourceResolverWrapper(toWrap);
+    }
+
+    @Override
+    public boolean isLive() {
+        return wrapped.isLive();
+    }
+
+    @Override
+    public void close() {
+        wrapped.close();
+    }
+
+    @Override
+    public String getUserID() {
+        return wrapped.getUserID();
+    }
+
+    @Nonnull
+    @Override
+    public Iterator<String> getAttributeNames() {
+        return wrapped.getAttributeNames();
+    }
+
+    @Override
+    public Object getAttribute(@Nonnull String name) {
+        return wrapped.getAttribute(name);
+    }
+
+    @Override
+    public void delete(@Nonnull Resource resource) throws PersistenceException {
+        wrapped.delete(resource);
+    }
+
+    /**
+     * Wraps the {@code Resource} obtained by calling {@code create} on the wrapped resource resolver.
+     *
+     * @param parent     The parent resource
+     * @param name       The name of the child resource - this is a plain name, not a path!
+     * @param properties Optional properties for the resource
+     * @return a wrapped resource obtained through the wrapped resource resolver
+     */
+    @Nonnull
+    @Override
+    public Resource create(@Nonnull Resource parent, @Nonnull String name, Map<String, Object> properties) throws PersistenceException {
+        return ResourceResolverResourceWrapper.wrap(this, wrapped.create(parent, name, properties));
+    }
+
+    @Override
+    public void revert() {
+        wrapped.revert();
+    }
+
+    @Override
+    public void commit() throws PersistenceException {
+        wrapped.commit();
+    }
+
+    @Override
+    public boolean hasChanges() {
+        return wrapped.hasChanges();
+    }
+
+    @Override
+    public String getParentResourceType(Resource resource) {
+        return wrapped.getParentResourceType(resource);
+    }
+
+    @Override
+    public String getParentResourceType(String resourceType) {
+        return wrapped.getParentResourceType(resourceType);
+    }
+
+    @Override
+    public boolean isResourceType(Resource resource, String resourceType) {
+        return wrapped.isResourceType(resource, resourceType);
+    }
+
+    @Override
+    public void refresh() {
+        wrapped.refresh();
+    }
+
+    /**
+     * Wraps the {@code Resource} obtained by calling {@code copy} on the wrapped resource resolver.
+     *
+     * @param srcAbsPath  the path of the resource to be copied.
+     * @param destAbsPath the location to which the resource at
+     *                    <code>srcAbsPath</code> is to be copied.
+     * @return a wrapped resource obtained through the wrapped resource resolver
+     */
+    @Override
+    public Resource copy(String srcAbsPath, String destAbsPath) throws PersistenceException {
+        return ResourceResolverResourceWrapper.wrap(this, wrapped.copy(srcAbsPath, destAbsPath));
+    }
+
+    /**
+     * Wraps the {@code Resource} obtained by calling {@code move} on the wrapped resource resolver.
+     *
+     * @param srcAbsPath  the path of the resource to be moved.
+     * @param destAbsPath the location to which the resource at
+     *                    <code>srcAbsPath</code> is to be moved.
+     * @return a wrapped resource obtained through the wrapped resource resolver
+     */
+    @Override
+    public Resource move(String srcAbsPath, String destAbsPath) throws PersistenceException {
+        return ResourceResolverResourceWrapper.wrap(this, wrapped.move(srcAbsPath, destAbsPath));
+    }
+
+    @Override
+    public <AdapterType> AdapterType adaptTo(@Nonnull Class<AdapterType> type) {
+        return wrapped.adaptTo(type);
+    }
+
+    /**
+     * {@code ResourceWrapper} that overwrites the {@link #getResourceResolver()} to return the {@link ResourceResolverWrapper}.
+     */
+    private static class ResourceResolverResourceWrapper extends ResourceWrapper {
+
+        private final ResourceResolverWrapper resolver;
+
+        /**
+         * Creates a new wrapper instance delegating all method calls to the given {@code resource}.
+         *
+         * @param resolver the wrapping resource resolver
+         * @param resource the wrapped resource
+         */
+        ResourceResolverResourceWrapper(ResourceResolverWrapper resolver, Resource resource) {
+            super(resource);
+            this.resolver = resolver;
+        }
+
+        /**
+         * Returns the wrapping resource resolver from which this resource was obtained.
+         *
+         * @return the wrapping resource resolver
+         */
+        @Override
+        public ResourceResolver getResourceResolver() {
+            return resolver;
+        }
+
+        private static Resource wrap(ResourceResolverWrapper resolver, Resource resource) {
+            if (resource != null) {
+                return new ResourceResolverResourceWrapper(resolver, resource);
+            }
+            return null;
+        }
+    }
+
+    /**
+     * {@code IteratorWrapper} that wraps every returned {@code Resource} with the {@code ResourceResolverResourceWrapper}.
+     *
+     * @see ResourceResolverResourceWrapper
+     */
+    private static class ResourceIteratorWrapper extends IteratorWrapper<Resource> {
+
+        private final ResourceResolverWrapper resolver;
+
+        public ResourceIteratorWrapper(ResourceResolverWrapper resolver, Iterator<Resource> wrappedIterator) {
+            super(wrappedIterator);
+            this.resolver = resolver;
+        }
+
+        @Override
+        public Resource next() {
+            return ResourceResolverResourceWrapper.wrap(resolver, super.next());
+        }
+    }
+}

Modified: sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/package-info.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/package-info.java?rev=1771928&r1=1771927&r2=1771928&view=diff
==============================================================================
--- sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/package-info.java (original)
+++ sling/trunk/bundles/api/src/main/java/org/apache/sling/api/wrappers/package-info.java Tue Nov 29 17:42:59 2016
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-@Version("2.5.0")
+@Version("2.6.0")
 package org.apache.sling.api.wrappers;
 
 import org.osgi.annotation.versioning.Version;

Added: sling/trunk/bundles/api/src/test/java/org/apache/sling/api/wrappers/ResourceResolverWrapperTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/src/test/java/org/apache/sling/api/wrappers/ResourceResolverWrapperTest.java?rev=1771928&view=auto
==============================================================================
--- sling/trunk/bundles/api/src/test/java/org/apache/sling/api/wrappers/ResourceResolverWrapperTest.java (added)
+++ sling/trunk/bundles/api/src/test/java/org/apache/sling/api/wrappers/ResourceResolverWrapperTest.java Tue Nov 29 17:42:59 2016
@@ -0,0 +1,431 @@
+/*******************************************************************************
+ * 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.api.wrappers;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceWrapper;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class ResourceResolverWrapperTest {
+
+    private static final String PATH = "path";
+    private static final String MAPPED_PATH = "mappedPath";
+    private static final String[] searchPaths = {"/apps", "/libs"};
+    private static final String QUERY = "query";
+    private static final String LANGUAGE = "language";
+    private static final String USER = "user";
+    private static final String ATTR_NAME = "attrName";
+    private ResourceResolver wrappedResolver;
+    private ResourceResolverWrapper underTest;
+
+    @Before
+    public void setUp() throws Exception {
+        wrappedResolver = mock(ResourceResolver.class);
+        when(wrappedResolver.getSearchPath()).thenReturn(searchPaths);
+        underTest = new ResourceResolverWrapper(wrappedResolver);
+    }
+
+    @Test
+    public void testResolve() throws Exception {
+        final HttpServletRequest request = mock(HttpServletRequest.class);
+        final Resource resource = mock(Resource.class);
+        when(resource.getPath()).thenReturn(PATH);
+        when(wrappedResolver.resolve(request, PATH)).thenReturn(resource);
+        final Resource result = underTest.resolve(request, PATH);
+
+        assertTrue(result instanceof ResourceWrapper);
+        assertEquals(underTest, result.getResourceResolver());
+        assertEquals(resource.getPath(), result.getPath());
+        verify(wrappedResolver).resolve(request, PATH);
+    }
+
+    @Test
+    public void testResolve1() throws Exception {
+        final Resource resource = mock(Resource.class);
+        when(resource.getPath()).thenReturn(PATH);
+        when(wrappedResolver.resolve(PATH)).thenReturn(resource);
+        final Resource result = underTest.resolve(PATH);
+
+        assertTrue(result instanceof ResourceWrapper);
+        assertEquals(underTest, result.getResourceResolver());
+        assertEquals(resource.getPath(), result.getPath());
+        verify(wrappedResolver).resolve(PATH);
+    }
+
+    @Test
+    public void testResolve2() throws Exception {
+        final HttpServletRequest request = mock(HttpServletRequest.class);
+        final Resource resource = mock(Resource.class);
+        when(resource.getPath()).thenReturn(PATH);
+        when(wrappedResolver.resolve(request)).thenReturn(resource);
+        final Resource result = underTest.resolve(request);
+
+        assertTrue(result instanceof ResourceWrapper);
+        assertEquals(underTest, result.getResourceResolver());
+        assertEquals(resource.getPath(), result.getPath());
+        verify(wrappedResolver).resolve(request);
+    }
+
+    @Test
+    public void testMap() throws Exception {
+        when(wrappedResolver.map(PATH)).thenReturn(MAPPED_PATH);
+
+        assertEquals(MAPPED_PATH, underTest.map(PATH));
+        verify(wrappedResolver).map(PATH);
+    }
+
+    @Test
+    public void testMap1() throws Exception {
+        final HttpServletRequest request = mock(HttpServletRequest.class);
+        when(wrappedResolver.map(request, PATH)).thenReturn(MAPPED_PATH);
+
+        assertEquals(MAPPED_PATH, underTest.map(request, PATH));
+        verify(wrappedResolver).map(request, PATH);
+    }
+
+    @Test
+    public void testGetResource() throws Exception {
+        final Resource resource = mock(Resource.class);
+        when(resource.getPath()).thenReturn(PATH);
+        when(wrappedResolver.getResource(PATH)).thenReturn(resource);
+
+        final Resource result = underTest.getResource(PATH);
+        assertTrue(result instanceof ResourceWrapper);
+        assertEquals(underTest, result.getResourceResolver());
+        assertEquals(resource.getPath(), result.getPath());
+        verify(wrappedResolver).getResource(PATH);
+    }
+
+    @Test
+    public void testGetResource1() throws Exception {
+        final Resource parent = mock(Resource.class);
+        final Resource resource = mock(Resource.class);
+        when(resource.getPath()).thenReturn(PATH);
+        when(wrappedResolver.getResource(parent, PATH)).thenReturn(resource);
+
+        final Resource result = underTest.getResource(parent, PATH);
+        assertTrue(result instanceof ResourceWrapper);
+        assertEquals(underTest, result.getResourceResolver());
+        assertEquals(resource.getPath(), result.getPath());
+        verify(wrappedResolver).getResource(parent, PATH);
+    }
+
+    @Test
+    public void testGetSearchPath() throws Exception {
+        assertArrayEquals(searchPaths, underTest.getSearchPath());
+        verify(wrappedResolver).getSearchPath();
+    }
+
+    @Test
+    public void testListChildren() throws Exception {
+        final Resource parent = mock(Resource.class);
+        final List<Resource> children = new ArrayList<>(1);
+        final Resource child = mock(Resource.class);
+        when(child.getPath()).thenReturn(PATH);
+        children.add(child);
+        when(wrappedResolver.listChildren(parent)).thenAnswer(new Answer<Iterator<Resource>>() {
+            @Override
+            public Iterator<Resource> answer(InvocationOnMock invocationOnMock) throws Throwable {
+                return children.iterator();
+            }
+        });
+
+        int index = 0;
+        Iterator<Resource> wrappedIterator = underTest.listChildren(parent);
+        assertTrue(wrappedIterator instanceof IteratorWrapper);
+        while (wrappedIterator.hasNext()) {
+            Resource result = wrappedIterator.next();
+            assertTrue(result instanceof ResourceWrapper);
+            assertEquals(PATH, result.getPath());
+            index++;
+        }
+        assertEquals(1, index);
+        verify(wrappedResolver).listChildren(parent);
+    }
+
+    @Test
+    public void testGetParent() throws Exception {
+        final Resource parent = mock(Resource.class);
+        final Resource child = mock(Resource.class);
+        when(parent.getPath()).thenReturn(PATH);
+        when(wrappedResolver.getParent(child)).thenReturn(parent);
+
+        Resource result = underTest.getParent(child);
+        assertTrue(result instanceof ResourceWrapper);
+        assertEquals(parent.getPath(), result.getPath());
+        verify(wrappedResolver).getParent(child);
+    }
+
+    @Test
+    public void testGetChildren() throws Exception {
+        final Resource parent = mock(Resource.class);
+        final List<Resource> children = new ArrayList<>(1);
+        final Resource child = mock(Resource.class);
+        when(child.getPath()).thenReturn(PATH);
+        children.add(child);
+        when(wrappedResolver.getChildren(parent)).thenReturn(children);
+        int index = 0;
+        Iterable<Resource> iterable = underTest.getChildren(parent);
+        for (Resource result : iterable) {
+            assertTrue(result instanceof ResourceWrapper);
+            assertEquals(PATH, result.getPath());
+            index++;
+        }
+        assertEquals(1, index);
+        verify(wrappedResolver).getChildren(parent);
+    }
+
+    @Test
+    public void testFindResources() throws Exception {
+        final List<Resource> children = new ArrayList<>(1);
+        final Resource child = mock(Resource.class);
+        when(child.getPath()).thenReturn(PATH);
+        children.add(child);
+        when(wrappedResolver.findResources(QUERY, LANGUAGE)).thenAnswer(new Answer<Iterator<Resource>>() {
+            @Override
+            public Iterator<Resource> answer(InvocationOnMock invocationOnMock) throws Throwable {
+                return children.iterator();
+            }
+        });
+
+        int index = 0;
+        final Iterator<Resource> wrappedIterator = underTest.findResources(QUERY, LANGUAGE);
+        assertTrue(wrappedIterator instanceof IteratorWrapper);
+        while (wrappedIterator.hasNext()) {
+            Resource result = wrappedIterator.next();
+            assertTrue(result instanceof ResourceWrapper);
+            assertEquals(PATH, result.getPath());
+            index++;
+        }
+        assertEquals(1, index);
+        verify(wrappedResolver).findResources(QUERY, LANGUAGE);
+    }
+
+    @Test
+    public void testQueryResources() throws Exception {
+        final Map<String, Object> expected = mock(Map.class);
+        final List<Map<String, Object>> list = new ArrayList<>();
+        list.add(expected);
+        when(wrappedResolver.queryResources(QUERY, LANGUAGE)).thenReturn(list.iterator());
+
+        int index = 0;
+        final Iterator<Map<String, Object>> iterator = underTest.queryResources(QUERY, LANGUAGE);
+        Map<String, Object> result = null;
+        while (iterator.hasNext()) {
+            result = iterator.next();
+            index++;
+        }
+        assertEquals(expected, result);
+        assertEquals(1, index);
+        verify(wrappedResolver).queryResources(QUERY, LANGUAGE);
+    }
+
+    @Test
+    public void testHasChildren() throws Exception {
+        final Resource resource = mock(Resource.class);
+        when(wrappedResolver.hasChildren(resource)).thenReturn(true);
+
+        assertTrue(underTest.hasChildren(resource));
+        verify(wrappedResolver).hasChildren(resource);
+    }
+
+    @Test
+    public void testClone() throws Exception {
+        final Map<String, Object> authenticationInfo = mock(Map.class);
+        final ResourceResolver clone = mock(ResourceResolver.class);
+        when(wrappedResolver.clone(authenticationInfo)).thenReturn(clone);
+
+        final ResourceResolver result = underTest.clone(authenticationInfo);
+        assertTrue(result instanceof ResourceResolverWrapper);
+        assertNotEquals(result, underTest);
+        verify(wrappedResolver).clone(authenticationInfo);
+    }
+
+    @Test
+    public void testIsLive() throws Exception {
+        when(wrappedResolver.isLive()).thenReturn(true);
+        assertTrue(underTest.isLive());
+        verify(wrappedResolver).isLive();
+    }
+
+    @Test
+    public void testClose() throws Exception {
+        underTest.close();
+        verify(wrappedResolver).close();
+    }
+
+    @Test
+    public void testGetUserID() throws Exception {
+        when(wrappedResolver.getUserID()).thenReturn(USER);
+        assertEquals(USER, underTest.getUserID());
+        verify(wrappedResolver).getUserID();
+    }
+
+    @Test
+    public void testGetAttributeNames() throws Exception {
+        final Iterator<String> attributeNames = mock(Iterator.class);
+        when(wrappedResolver.getAttributeNames()).thenReturn(attributeNames);
+
+        assertEquals(attributeNames, underTest.getAttributeNames());
+        verify(wrappedResolver).getAttributeNames();
+    }
+
+    @Test
+    public void testGetAttribute() throws Exception {
+        final Object obj = mock(Object.class);
+        when(wrappedResolver.getAttribute(ATTR_NAME)).thenReturn(obj);
+
+        assertEquals(obj, underTest.getAttribute(ATTR_NAME));
+        verify(wrappedResolver).getAttribute(ATTR_NAME);
+    }
+
+    @Test
+    public void testDelete() throws Exception {
+        final Resource toDelete = mock(Resource.class);
+        underTest.delete(toDelete);
+        verify(wrappedResolver).delete(toDelete);
+    }
+
+    @Test
+    public void testCreate() throws Exception {
+        final Resource parent = mock(Resource.class);
+        final String name = "aName";
+        final Map<String, Object> properties = new HashMap<String, Object>(){{
+            put("jcr:primaryType", "nt:unstructured");
+        }};
+        final Resource expected = mock(Resource.class);
+        when(expected.getParent()).thenReturn(parent);
+        when(expected.getName()).thenReturn(name);
+        when(wrappedResolver.create(parent, name, properties)).thenReturn(expected);
+
+        final Resource result = underTest.create(parent, name, properties);
+        assertTrue(result instanceof ResourceWrapper);
+        assertEquals(parent, result.getParent());
+        assertEquals(name, result.getName());
+        verify(wrappedResolver).create(parent, name, properties);
+    }
+
+    @Test
+    public void testRevert() throws Exception {
+        underTest.revert();
+        verify(wrappedResolver).revert();
+    }
+
+    @Test
+    public void testCommit() throws Exception {
+        underTest.commit();
+        verify(wrappedResolver).commit();
+    }
+
+    @Test
+    public void testHasChanges() throws Exception {
+        when(wrappedResolver.hasChanges()).thenReturn(true);
+        assertTrue(underTest.hasChanges());
+        verify(wrappedResolver).hasChanges();
+    }
+
+    @Test
+    public void testGetParentResourceType() throws Exception {
+        final String rt = "rt";
+        final Resource resource = mock(Resource.class);
+        when(wrappedResolver.getParentResourceType(resource)).thenReturn(rt);
+
+        assertEquals(rt, underTest.getParentResourceType(resource));
+        verify(wrappedResolver).getParentResourceType(resource);
+    }
+
+    @Test
+    public void testGetParentResourceType1() throws Exception {
+        final String rt = "rt";
+        final String rtt = "rtt";
+        when(wrappedResolver.getParentResourceType(rt)).thenReturn(rtt);
+
+        assertEquals(rtt, underTest.getParentResourceType(rt));
+        verify(wrappedResolver).getParentResourceType(rt);
+    }
+
+    @Test
+    public void testIsResourceType() throws Exception {
+        final Resource resource = mock(Resource.class);
+        final String rt = "rt";
+        when(wrappedResolver.isResourceType(resource, rt)).thenReturn(true);
+
+        assertTrue(underTest.isResourceType(resource, rt));
+        verify(wrappedResolver).isResourceType(resource, rt);
+    }
+
+    @Test
+    public void testRefresh() throws Exception {
+        underTest.refresh();
+        verify(wrappedResolver).refresh();
+    }
+
+    @Test
+    public void testCopy() throws Exception {
+        final String source = "source";
+        final String destination = "destination";
+        final Resource expected = mock(Resource.class);
+        when(expected.getPath()).thenReturn(destination);
+        when(wrappedResolver.copy(source, destination)).thenReturn(expected);
+
+        final Resource result = underTest.copy(source, destination);
+        assertTrue(result instanceof ResourceWrapper);
+        assertEquals(underTest, result.getResourceResolver());
+        assertEquals(destination, result.getPath());
+        verify(wrappedResolver).copy(source, destination);
+    }
+
+    @Test
+    public void testMove() throws Exception {
+        final String source = "source";
+        final String destination = "destination";
+        final Resource expected = mock(Resource.class);
+        when(expected.getPath()).thenReturn(destination);
+        when(wrappedResolver.move(source, destination)).thenReturn(expected);
+
+        final Resource result = underTest.move(source, destination);
+        assertTrue(result instanceof ResourceWrapper);
+        assertEquals(underTest, result.getResourceResolver());
+        assertEquals(destination, result.getPath());
+        verify(wrappedResolver).move(source, destination);
+    }
+
+    @Test
+    public void testAdaptTo() throws Exception {
+        List list = mock(List.class);
+        when(wrappedResolver.adaptTo(List.class)).thenReturn(list);
+
+        assertEquals(list, underTest.adaptTo(List.class));
+        verify(wrappedResolver).adaptTo(List.class);
+    }
+}