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

svn commit: r1709747 [3/4] - in /sling/trunk/bundles/resourceresolver: ./ src/main/java/org/apache/sling/resourceresolver/impl/ src/main/java/org/apache/sling/resourceresolver/impl/helper/ src/main/java/org/apache/sling/resourceresolver/impl/legacy/ sr...

Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/SecureResourceProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/SecureResourceProvider.java?rev=1709747&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/SecureResourceProvider.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/SecureResourceProvider.java Wed Oct 21 08:23:09 2015
@@ -0,0 +1,134 @@
+/*
+ * 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.resourceresolver.impl.providers.stateful;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.security.ResourceAccessSecurity;
+import org.apache.sling.resourceresolver.impl.ResourceAccessSecurityTracker;
+import org.apache.sling.resourceresolver.impl.ResourceResolverImpl;
+import org.apache.sling.spi.resource.provider.ResourceProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This wrappers add the Sling security layer (see
+ * {@link ResourceAccessSecurity}) to the underlying {@link ResourceProvider}.
+ */
+public class SecureResourceProvider extends StatefulResourceProviderWrapper {
+
+    private static final Logger logger = LoggerFactory.getLogger(ResourceResolverImpl.class);
+
+    private final ResourceAccessSecurityTracker tracker;
+
+    public SecureResourceProvider(StatefulResourceProvider rp, ResourceAccessSecurityTracker tracker) {
+        super(rp);
+        if (tracker == null) {
+            logger.warn("ResourceAccessSecurityTracker is null. Resource-level security will be disabled.");
+        }
+        this.tracker = tracker;
+    }
+
+    @Override
+    public Resource create(final String path, Map<String, Object> properties, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
+        if (isAllowed(new SecurityTest() {
+            @Override
+            public boolean isAllowed(ResourceAccessSecurity security) {
+                return security.canCreate(path, getResourceResolver());
+            }
+        })) {
+            return rp.create(path, properties, parentProviders);
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public void delete(final Resource resource, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
+        if (isAllowed(new SecurityTest() {
+            @Override
+            public boolean isAllowed(ResourceAccessSecurity security) {
+                return security.canDelete(resource);
+            }
+        })) {
+            rp.delete(resource, parentProviders);
+        }
+    }
+
+    @Override
+    public Iterator<Resource> findResources(String query, String language) {
+        return wrapIterator(rp.findResources(query, language));
+    }
+
+    private Iterator<Resource> wrapIterator(Iterator<Resource> iterator) {
+        if (tracker == null) {
+            return iterator;
+        } else {
+            return new SecureIterator(iterator);
+        }
+    }
+
+    private boolean isAllowed(SecurityTest test) {
+        if (tracker == null) {
+            return true;
+        }
+        boolean allowed = true;
+        if (tracker.getProviderResourceAccessSecurity() != null) {
+            allowed = allowed && test.isAllowed(tracker.getProviderResourceAccessSecurity());
+        }
+        if (tracker.getApplicationResourceAccessSecurity() != null) {
+            allowed = allowed && test.isAllowed(tracker.getApplicationResourceAccessSecurity());
+        }
+        return allowed;
+    }
+
+    private static interface SecurityTest {
+        boolean isAllowed(ResourceAccessSecurity security);
+    }
+
+    private class SecureIterator extends AbstractIterator<Resource> {
+
+        private final Iterator<Resource> iterator;
+
+        public SecureIterator(Iterator<Resource> iterator) {
+            this.iterator = iterator;
+        }
+
+        @Override
+        protected Resource seek() {
+            while (iterator.hasNext()) {
+                Resource resource = iterator.next();
+                if (resource != null && tracker.getProviderResourceAccessSecurity() != null) {
+                    resource = tracker.getProviderResourceAccessSecurity().getReadableResource(resource);
+                }
+                if (resource != null && tracker.getApplicationResourceAccessSecurity() != null) {
+                    resource = tracker.getApplicationResourceAccessSecurity().getReadableResource(resource);
+                }
+                if (resource != null) {
+                    return resource;
+                }
+            }
+            return null;
+        }
+    }
+}

Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/StatefulResourceProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/StatefulResourceProvider.java?rev=1709747&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/StatefulResourceProvider.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/StatefulResourceProvider.java Wed Oct 21 08:23:09 2015
@@ -0,0 +1,174 @@
+/*
+ * 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.resourceresolver.impl.providers.stateful;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+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.query.Query;
+import org.apache.sling.api.resource.query.QueryInstructions;
+import org.apache.sling.api.resource.query.QueryManager;
+import org.apache.sling.spi.resource.provider.JCRQueryProvider;
+import org.apache.sling.spi.resource.provider.QueryResult;
+import org.apache.sling.spi.resource.provider.ResolveContext;
+import org.apache.sling.spi.resource.provider.ResourceProvider;
+
+/**
+ * This interface represents a {@link ResourceProvider} and its authentication
+ * info. It's meant to be used only in the o.a.s.resourceresolver.impl bundle to
+ * avoid passing authentication state with every call to any resource provider
+ * method.
+ */
+public interface StatefulResourceProvider {
+
+    /**
+     * Returns the resource resolver associated to this {@link StatefulResourceProvider}.
+     */
+    ResourceResolver getResourceResolver();
+
+    /**
+     * @see ResourceProvider#logout(Object)
+     */
+    void logout();
+
+    /**
+     * @see ResourceProvider#refresh(org.apache.sling.spi.resource.provider.ResolveContext)
+     */
+    void refresh();
+
+    /**
+     * @see ResourceProvider#isLive(org.apache.sling.spi.resource.provider.ResolveContext)
+     */
+    boolean isLive();
+
+    /**
+     * @see ResourceProvider#getParent(org.apache.sling.spi.resource.provider.ResolveContext, Resource)
+     */
+    @CheckForNull
+    Resource getParent(final @Nonnull Resource child, final List<StatefulResourceProvider> parentProviders);
+
+    /**
+     * @see ResourceProvider#getResource(org.apache.sling.spi.resource.provider.ResolveContext, String, Resource)
+     */
+    @CheckForNull
+    Resource getResource(@Nonnull final String path, @CheckForNull final Resource parent,
+            final Map<String, String> parameters, final boolean isResolve,
+            final List<StatefulResourceProvider> parentProviders);
+
+    /**
+     * @see ResourceProvider#listChildren(org.apache.sling.spi.resource.provider.ResolveContext, Resource)
+     */
+    @CheckForNull
+    Iterator<Resource> listChildren(final @Nonnull Resource parent, final List<StatefulResourceProvider> parentProviders);
+
+    /**
+     * @see ResourceProvider#getAttributeNames(org.apache.sling.spi.resource.provider.ResolveContext)
+     */
+    Collection<String> getAttributeNames();
+
+    /**
+     * @see ResourceProvider#getAttribute(org.apache.sling.spi.resource.provider.ResolveContext, String)
+     */
+    Object getAttribute(final @Nonnull String name);
+
+    /**
+     * @see ResourceProvider#create(org.apache.sling.spi.resource.provider.ResolveContext, String, Map)
+     */
+    Resource create(final String path, final Map<String, Object> properties, final List<StatefulResourceProvider> parentProviders) throws PersistenceException;
+
+    /**
+     * @see ResourceProvider#delete(org.apache.sling.spi.resource.provider.ResolveContext, Resource)
+     */
+    void delete(final @Nonnull Resource resource, final List<StatefulResourceProvider> parentProviders) throws PersistenceException;
+
+    /**
+     * @see ResourceProvider#revert(org.apache.sling.spi.resource.provider.ResolveContext)
+     */
+    void revert();
+
+    /**
+     * @see ResourceProvider#commit(org.apache.sling.spi.resource.provider.ResolveContext)
+     */
+    void commit() throws PersistenceException;
+
+    /**
+     * @see ResourceProvider#hasChanges(org.apache.sling.spi.resource.provider.ResolveContext)
+     */
+    boolean hasChanges();
+
+    /**
+     * @see QueryManager#find(ResourceResolver, Query, QueryInstructions)
+     */
+    @CheckForNull
+    QueryResult find(@Nonnull Query q, @Nonnull QueryInstructions qi);
+
+    /**
+     * @see JCRQueryProvider#getSupportedLanguages(org.apache.sling.spi.resource.provider.ResolveContext)
+     */
+    @CheckForNull
+    String[] getSupportedLanguages();
+
+    /**
+     * @see JCRQueryProvider#findResources(org.apache.sling.spi.resource.provider.ResolveContext, String, String)
+     */
+    @CheckForNull
+    Iterator<Resource> findResources(String query, String language);
+
+    /**
+     * @see JCRQueryProvider#queryResources(org.apache.sling.spi.resource.provider.ResolveContext, String, String)
+     */
+    @CheckForNull
+    Iterator<Map<String, Object>> queryResources(String query, String language);
+
+    /**
+     * @see ResourceProvider#adaptTo(org.apache.sling.spi.resource.provider.ResolveContext, Class)
+     */
+    @CheckForNull
+    <AdapterType> AdapterType adaptTo(final @Nonnull Class<AdapterType> type);
+
+    /**
+     * @see ResourceProvider#copy(org.apache.sling.spi.resource.provider.ResolveContext, String, String)
+     */
+    boolean copy(final String srcAbsPath, final String destAbsPath, final List<StatefulResourceProvider> parentProviders) throws PersistenceException;
+
+    /**
+     * @see ResourceProvider#move(org.apache.sling.spi.resource.provider.ResolveContext, String, String)
+     */
+    boolean move(final String srcAbsPath, final String destAbsPath, final List<StatefulResourceProvider> parentProviders) throws PersistenceException;
+
+    /**
+     * @return Wrapped ResourceProvider
+     */
+    ResourceProvider<Object> getResourceProvider();
+
+    /**
+     * @return Context for the wrapped ResourceProvider
+     * @throws LoginException 
+     */
+    ResolveContext<Object> getContext(Map<String, String> parameters) throws LoginException;
+}

Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/StatefulResourceProviderWrapper.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/StatefulResourceProviderWrapper.java?rev=1709747&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/StatefulResourceProviderWrapper.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/StatefulResourceProviderWrapper.java Wed Oct 21 08:23:09 2015
@@ -0,0 +1,158 @@
+/*
+ * 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.resourceresolver.impl.providers.stateful;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+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.query.Query;
+import org.apache.sling.api.resource.query.QueryInstructions;
+import org.apache.sling.spi.resource.provider.QueryResult;
+import org.apache.sling.spi.resource.provider.ResolveContext;
+import org.apache.sling.spi.resource.provider.ResourceProvider;
+
+public class StatefulResourceProviderWrapper implements StatefulResourceProvider {
+
+    protected final StatefulResourceProvider rp;
+
+    public StatefulResourceProviderWrapper(StatefulResourceProvider rp) {
+        this.rp = rp;
+    }
+
+    @Override
+    public void logout() {
+        rp.logout();
+    }
+
+    @Override
+    public void refresh() {
+        rp.refresh();
+    }
+
+    @Override
+    public boolean isLive() {
+        return rp.isLive();
+    }
+
+    @Override
+    public Resource getParent(Resource child, List<StatefulResourceProvider> parentProviders) {
+        return rp.getParent(child, parentProviders);
+    }
+
+    @Override
+    public Resource getResource(String path, Resource parent, Map<String, String> parameters, boolean isResolve,  List<StatefulResourceProvider> parentProviders) {
+        return rp.getResource(path, parent, parameters, isResolve, parentProviders);
+    }
+
+    @Override
+    public Iterator<Resource> listChildren(Resource parent, List<StatefulResourceProvider> parentProviders) {
+        return rp.listChildren(parent, parentProviders);
+    }
+
+    @Override
+    public Collection<String> getAttributeNames() {
+        return rp.getAttributeNames();
+    }
+
+    @Override
+    public Object getAttribute(String name) {
+        return rp.getAttribute(name);
+    }
+
+    @Override
+    public Resource create(String path, Map<String, Object> properties, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
+        return rp.create(path, properties, parentProviders);
+    }
+
+    @Override
+    public void delete(Resource resource, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
+        rp.delete(resource, parentProviders);
+    }
+
+    @Override
+    public void revert() {
+        rp.revert();
+    }
+
+    @Override
+    public void commit() throws PersistenceException {
+        rp.commit();
+    }
+
+    @Override
+    public boolean hasChanges() {
+        return rp.hasChanges();
+    }
+
+    @Override
+    public QueryResult find(Query q, QueryInstructions qi) {
+        return rp.find(q, qi);
+    }
+
+    @Override
+    public String[] getSupportedLanguages() {
+        return rp.getSupportedLanguages();
+    }
+
+    @Override
+    public Iterator<Resource> findResources(String query, String language) {
+        return rp.findResources(query, language);
+    }
+
+    @Override
+    public Iterator<Map<String, Object>> queryResources(String query, String language) {
+        return rp.queryResources(query, language);
+    }
+
+    @Override
+    public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+        return rp.adaptTo(type);
+    }
+
+    @Override
+    public boolean copy(String srcAbsPath, String destAbsPath, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
+        return rp.copy(srcAbsPath, destAbsPath, parentProviders);
+    }
+
+    @Override
+    public boolean move(String srcAbsPath, String destAbsPath, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
+        return rp.move(srcAbsPath, destAbsPath, parentProviders);
+    }
+
+    @Override
+    public ResourceResolver getResourceResolver() {
+        return rp.getResourceResolver();
+    }
+
+    @Override
+    public ResourceProvider<Object> getResourceProvider() {
+        return rp.getResourceProvider();
+    }
+
+    @Override
+    public ResolveContext<Object> getContext(Map<String, String> parameters) throws LoginException {
+        return rp.getContext(parameters);
+    }
+}

Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/Node.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/Node.java?rev=1709747&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/Node.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/Node.java Wed Oct 21 08:23:09 2015
@@ -0,0 +1,67 @@
+/*
+ * 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.resourceresolver.impl.providers.tree;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+public class Node<T> {
+
+    private T value;
+
+    private Map<String, Node<T>> children;
+
+    public boolean hasChild(String name) {
+        return children != null && children.containsKey(name);
+    }
+
+    public Node<T> getChild(String name) {
+        if (children != null) {
+            return children.get(name);
+        } else {
+            return null;
+        }
+    }
+
+    Node<T> addChild(String name) {
+        if (children == null) {
+            children = new HashMap<String, Node<T>>();
+        }
+        Node<T> newNode = new Node<T>();
+        children.put(name, newNode);
+        return newNode;
+    }
+
+    void setValue(T value) {
+        this.value = value;
+    }
+
+    public T getValue() {
+        return value;
+    }
+
+    public Map<String, Node<T>> getChildren() {
+        if (children == null) {
+            return Collections.emptyMap();
+        } else {
+            return children;
+        }
+    }
+}
\ No newline at end of file

Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/PathSegmentIterator.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/PathSegmentIterator.java?rev=1709747&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/PathSegmentIterator.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/PathSegmentIterator.java Wed Oct 21 08:23:09 2015
@@ -0,0 +1,58 @@
+/*
+ * 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.resourceresolver.impl.providers.tree;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+public class PathSegmentIterator implements Iterator<String> {
+
+    private final String path;
+
+    private int index = 0;
+
+    public PathSegmentIterator(String path, int index) {
+        this.path = path;
+        this.index = index;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return index < path.length();
+    }
+
+    @Override
+    public String next() {
+        if (!hasNext()) {
+            throw new NoSuchElementException();
+        }
+        int nextIndex = path.indexOf('/', index);
+        if (nextIndex == -1) {
+            nextIndex = path.length();
+        }
+        String result = path.substring(index, nextIndex);
+        index = nextIndex + 1;
+        return result;
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+}

Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/PathTree.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/PathTree.java?rev=1709747&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/PathTree.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/PathTree.java Wed Oct 21 08:23:09 2015
@@ -0,0 +1,92 @@
+/*
+ * 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.resourceresolver.impl.providers.tree;
+
+import static org.apache.commons.lang.StringUtils.split;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+public class PathTree<T extends Pathable> {
+
+    private Node<T> root;
+
+    public PathTree(List<T> values) {
+        this.root = new Node<T>();
+        for (T v : values) {
+            addNewValue(v);
+        }
+    }
+
+    private void addNewValue(T value) {
+        Node<T> node = root;
+        for (String segment : split(value.getPath(), '/')) {
+            if (node.hasChild(segment)) {
+                node = node.getChild(segment);
+            } else {
+                node = node.addChild(segment);
+            }
+        }
+        node.setValue(value);
+    }
+
+    public List<T> getMatchingNodes(String path) {
+        if (path == null || path.isEmpty() || path.charAt(0) != '/') {
+            return Collections.emptyList();
+        }
+        List<T> values = new ArrayList<T>();
+
+        if (root.getValue() != null) {
+            values.add(root.getValue());
+        }
+
+        Node<T> node = root;
+        Iterator<String> it = new PathSegmentIterator(path, 1);
+        while (it.hasNext()) {
+            String segment = it.next();
+            node = node.getChild(segment);
+            if (node == null) {
+                break;
+            } else {
+                if (node.getValue() != null) {
+                    values.add(node.getValue());
+                }
+            }
+        }
+        return values;
+    }
+
+    public Node<T> getNode(String path) {
+        if (path == null || path.isEmpty() || path.charAt(0) != '/') {
+            return null;
+        }
+        Node<T> node = root;
+        Iterator<String> it = new PathSegmentIterator(path, 1);
+        while (it.hasNext()) {
+            String segment = it.next();
+            node = node.getChild(segment);
+            if (node == null) {
+                return null;
+            }
+        }
+        return node;
+    }
+}

Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/Pathable.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/Pathable.java?rev=1709747&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/Pathable.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/Pathable.java Wed Oct 21 08:23:09 2015
@@ -0,0 +1,25 @@
+/*
+ * 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.resourceresolver.impl.providers.tree;
+
+public interface Pathable {
+
+    String getPath();
+
+}

Modified: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/MockedResourceResolverImplTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/MockedResourceResolverImplTest.java?rev=1709747&r1=1709746&r2=1709747&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/MockedResourceResolverImplTest.java (original)
+++ sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/MockedResourceResolverImplTest.java Wed Oct 21 08:23:09 2015
@@ -30,20 +30,25 @@ import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Random;
 import java.util.Set;
 
 import javax.servlet.http.HttpServletRequest;
 
 import org.apache.sling.api.resource.LoginException;
-import org.apache.sling.api.resource.QueriableResourceProvider;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceMetadata;
-import org.apache.sling.api.resource.ResourceProvider;
-import org.apache.sling.api.resource.ResourceProviderFactory;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceResolverFactory;
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.api.wrappers.ValueMapDecorator;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderHandler;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderInfo;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderStorage;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderTracker;
+import org.apache.sling.spi.resource.provider.JCRQueryProvider;
+import org.apache.sling.spi.resource.provider.ResolveContext;
+import org.apache.sling.spi.resource.provider.ResourceProvider;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -56,7 +61,9 @@ import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceReference;
 import org.osgi.service.component.ComponentContext;
+import org.osgi.service.event.Event;
 import org.osgi.service.event.EventAdmin;
 
 /**
@@ -76,11 +83,10 @@ public class MockedResourceResolverImplT
 
     private ResourceResolverFactoryActivator activator;
 
-    @Mock
-    private ComponentContext componentContext;
+    private List<ResourceProviderHandler> handlers = new ArrayList<ResourceProviderHandler>();
 
     @Mock
-    private EventAdmin eventAdmin;
+    private ComponentContext componentContext;
 
     @Mock
     private BundleContext bundleContext;
@@ -91,6 +97,13 @@ public class MockedResourceResolverImplT
     @Mock
     private BundleContext usingBundleContext;
 
+    @Mock
+    private ResourceProviderTracker resourceProviderTracker;
+
+    @SuppressWarnings("rawtypes")
+    @Mock
+    private JCRQueryProvider queryProvider;
+
     private Map<String, Object> services = new HashMap<String, Object>();
 
     private Map<String, Object> serviceProperties = new HashMap<String, Object>();
@@ -98,37 +111,25 @@ public class MockedResourceResolverImplT
     private ResourceResolverFactoryImpl resourceResolverFactory;
 
     @Mock
-    private ResourceProvider resourceProvider;
-
-    @Mock
-    private ResourceProviderFactory resourceProviderFactory;
-
-    /**
-     * the factory creates these.
-     */
-    @Mock
-    private ResourceProvider factoryResourceProvider;
-
-    @Mock
-    private ResourceProvider factoryAdministrativeResourceProvider;
+    private ResourceProvider<?> resourceProvider;
 
     /**
      * deals with /etc resolution.
      */
     @Mock
-    private ResourceProvider mappingResourceProvider;
+    private ResourceProvider<?> mappingResourceProvider;
 
     /**
      * deals with /apps and /libs resolution.
      */
     @Mock
-    private ResourceProvider appsResourceProvider;
+    private ResourceProvider<?> appsResourceProvider;
     
     /**
      * QueriableResourceProviders
      */
     @Mock
-    private QueriableResourceProvider queriableResourceProviderA;
+    private ResourceProvider<?> queriableResourceProviderA;
 
 
     public MockedResourceResolverImplTest() {
@@ -143,51 +144,26 @@ public class MockedResourceResolverImplT
         Mockito.when(componentContext.getProperties()).thenReturn(buildBundleProperties());
         Mockito.when(componentContext.getBundleContext()).thenReturn(
             bundleContext);
-        activator.eventAdmin = eventAdmin;
+
         activator.resourceAccessSecurityTracker = new ResourceAccessSecurityTracker();
+        activator.resourceProviderTracker = resourceProviderTracker;
 
-        activator.bindResourceProvider(resourceProvider,
-            buildResourceProviderProperties("org.apache.sling.resourceresolver.impl.DummyTestProvider",
-                10L,
-                new String[] { "/single" }));
+        handlers.add(createRPHandler(resourceProvider, "org.apache.sling.resourceresolver.impl.DummyTestProvider", 10L, "/single"));
 
         // setup mapping resources at /etc/map to exercise vanity etc.
         // hmm, can't provide the resolver since its not up and ready.
         // mapping almost certainly work properly until this can be setup correctly.
         buildMappingResource("/etc/map", mappingResourceProvider, null);
 
-        activator.bindResourceProvider(mappingResourceProvider,
-            buildResourceProviderProperties("org.apache.sling.resourceresolver.impl.MapProvider",
-                11L,
-                new String[] { "/etc" }));
-
-        // bind a ResourceProviderFactory to satidy the pre-requirements
-        Mockito.when(resourceProviderFactory.getResourceProvider(null)).thenReturn(
-            factoryResourceProvider);
-        Mockito.when(
-            resourceProviderFactory.getResourceProvider(Mockito.anyMap())).thenReturn(
-            factoryResourceProvider);
-        Mockito.when(
-            resourceProviderFactory.getAdministrativeResourceProvider(null)).thenReturn(
-            factoryAdministrativeResourceProvider);
-        Mockito.when(
-            resourceProviderFactory.getAdministrativeResourceProvider(Mockito.anyMap())).thenReturn(
-            factoryAdministrativeResourceProvider);
-
-        activator.bindResourceProviderFactory(resourceProviderFactory,
-            buildResourceProviderProperties("org.apache.sling.resourceresolver.impl.DummyTestProviderFactory",
-                12L,
-                new String[] { "/factory" } ));
-
-        activator.bindResourceProvider(appsResourceProvider,
-            buildResourceProviderProperties("org.apache.sling.resourceresolver.impl.AppsProvider",
-                13L,
-                new String[] { "/apps", "/libs" }));
-
-        activator.bindResourceProvider(queriableResourceProviderA,
-                buildResourceProviderProperties("org.apache.sling.resourceresolver.impl.QueriableResourceProviderA",
-                    14L,
-                    new String[] { "/searchA" }));
+        handlers.add(createRPHandler(mappingResourceProvider, "org.apache.sling.resourceresolver.impl.MapProvider", 11L, "/etc"));
+        handlers.add(createRPHandler(appsResourceProvider, "org.apache.sling.resourceresolver.impl.AppsProvider", 12L, "/libs"));
+        handlers.add(createRPHandler(appsResourceProvider, "org.apache.sling.resourceresolver.impl.AppsProvider", 13L, "/apps"));
+        handlers.add(createRPHandler(queriableResourceProviderA, "org.apache.sling.resourceresolver.impl.QueriableResourceProviderA", 14L, "/searchA"));
+        Mockito.when(queriableResourceProviderA.getJCRQueryProvider()).thenReturn(queryProvider);
+
+        ResourceProviderStorage storage = new ResourceProviderStorage(handlers);
+
+        Mockito.when(resourceProviderTracker.getResourceProviderStorage()).thenReturn(storage);
 
         // activate the components.
         activator.activate(componentContext);
@@ -224,8 +200,33 @@ public class MockedResourceResolverImplT
         resourceResolverFactory = (ResourceResolverFactoryImpl) rrf;
     }
 
+    public static ResourceProviderHandler createRPHandler(ResourceProvider<?> rp, String pid, long ranking,
+            String path) {
+        ServiceReference ref = Mockito.mock(ServiceReference.class);        
+        BundleContext bc = Mockito.mock(BundleContext.class);
+        Mockito.when(bc.getService(Mockito.eq(ref))).thenReturn(rp);
+        Mockito.when(ref.getProperty(Mockito.eq(Constants.SERVICE_ID))).thenReturn(new Random().nextLong());
+        Mockito.when(ref.getProperty(Mockito.eq(Constants.SERVICE_PID))).thenReturn(pid);
+        Mockito.when(ref.getProperty(Mockito.eq(Constants.SERVICE_RANKING))).thenReturn(ranking);
+        Mockito.when(ref.getProperty(Mockito.eq(ResourceProvider.PROPERTY_ROOT))).thenReturn(path);
+        Mockito.when(ref.getProperty(Mockito.eq(ResourceProvider.PROPERTY_MODIFIABLE))).thenReturn(true);
+        Mockito.when(ref.getProperty(Mockito.eq(ResourceProvider.PROPERTY_ATTRIBUTABLE))).thenReturn(true);
+        Mockito.when(ref.getProperty(Mockito.eq(ResourceProvider.PROPERTY_ADAPTABLE))).thenReturn(true);
+
+        ResourceProviderInfo info = new ResourceProviderInfo(ref);
+        return new ResourceProviderHandler(bc, info, new EventAdmin() {
+            @Override
+            public void sendEvent(Event event) {
+            }
+            @Override
+            public void postEvent(Event event) {
+            }
+        });
+    }
+
+    @SuppressWarnings("unchecked")
     private Resource buildMappingResource(String path,
-            ResourceProvider provider, ResourceResolver resourceResolver) {
+            ResourceProvider<?> provider, ResourceResolver resourceResolver) {
         List<Resource> localHostAnyList = new ArrayList<Resource>();
         localHostAnyList.add(buildResource(path+"/http/example.com.80/cgi-bin", EMPTY_RESOURCE_LIST, resourceResolver, provider, "sling:internalRedirect", "/scripts" ));
         localHostAnyList.add(buildResource(path+"/http/example.com.80/gateway", EMPTY_RESOURCE_LIST, resourceResolver, provider,"sling:internalRedirect", "http://gbiv.com"));
@@ -238,25 +239,13 @@ public class MockedResourceResolverImplT
         mappingChildren.add(buildResource(path+"/http/localhost_any", localHostAnyList, resourceResolver, provider,"sling:match", "localhost\\.\\d*", "sling:internalRedirect", "/content"));
 
         Resource etcMapResource = buildResource(path+"/http", mappingChildren);
-        Mockito.when(provider.getResource(Mockito.any(ResourceResolver.class), Mockito.eq(path))).thenReturn(etcMapResource);
+        Mockito.when(provider.getResource(Mockito.any(ResolveContext.class), Mockito.eq(path), Mockito.any(Resource.class))).thenReturn(etcMapResource);
         return etcMapResource;
     }
 
     @After
     public void after() {
-        activator.unbindResourceProvider(resourceProvider,
-            buildResourceProviderProperties("org.apache.sling.resourceresolver.impl.DummyTestProvider",
-                                            10L,
-                                            new String[] { "/single" }));
-        activator.unbindResourceProvider(mappingResourceProvider,
-            buildResourceProviderProperties("org.apache.sling.resourceresolver.impl.MapProvider",
-                                            11L,
-                                            new String[] { "/etc" }));
-        activator.bindResourceProviderFactory(resourceProviderFactory,
-            buildResourceProviderProperties("org.apache.sling.resourceresolver.impl.DummyTestProviderFactory",
-                                            12L,
-                                            new String[] { "/factory" } ));
-
+        handlers.clear();
     }
 
     /**
@@ -278,7 +267,7 @@ public class MockedResourceResolverImplT
      * @return
      */
     private Resource buildResource(String fullpath, Iterable<Resource> children) {
-        return buildResource(fullpath, children, null, null, null);
+        return buildResource(fullpath, children, null, null, new String[0]);
     }
     
     /** Build a List of ValueMap */
@@ -299,7 +288,8 @@ public class MockedResourceResolverImplT
      * @param resourceResolver
      * @return
      */
-    private Resource buildResource(String fullpath, Iterable<Resource> children, ResourceResolver resourceResolver, ResourceProvider provider, String ... properties) {
+    @SuppressWarnings("unchecked")
+    private Resource buildResource(String fullpath, Iterable<Resource> children, ResourceResolver resourceResolver, ResourceProvider<?> provider, String ... properties) {
         Resource resource = Mockito.mock(Resource.class);
         Mockito.when(resource.getName()).thenReturn(getName(fullpath));
         Mockito.when(resource.getPath()).thenReturn(fullpath);
@@ -310,14 +300,8 @@ public class MockedResourceResolverImplT
 
         // register the resource with the provider
         if ( provider != null ) {
-            Mockito.when(provider.listChildren(resource)).thenReturn(children.iterator());
-            if ( resourceResolver != null) {
-                Mockito.when(provider.getResource(Mockito.eq(resourceResolver), Mockito.eq(fullpath))).thenReturn(resource);
-                Mockito.when(provider.getResource(Mockito.eq(resourceResolver), Mockito.any(HttpServletRequest.class), Mockito.eq(fullpath))).thenReturn(resource);
-            } else {
-                Mockito.when(provider.getResource(Mockito.any(ResourceResolver.class), Mockito.eq(fullpath))).thenReturn(resource);
-                Mockito.when(provider.getResource(Mockito.any(ResourceResolver.class), Mockito.any(HttpServletRequest.class), Mockito.eq(fullpath))).thenReturn(resource);
-            }
+            Mockito.when(provider.listChildren(Mockito.any(ResolveContext.class), Mockito.eq(resource))).thenReturn(children.iterator());
+            Mockito.when(provider.getResource(Mockito.any(ResolveContext.class), Mockito.eq(fullpath), Mockito.any(Resource.class))).thenReturn(resource);
         }
         if ( properties != null ) {
             ValueMap vm = new SimpleValueMapImpl();
@@ -346,29 +330,6 @@ public class MockedResourceResolverImplT
         return fullpath.substring(n+1);
     }
 
-
-    /**
-     * Build properties for a resource provider.
-     * @param servicePID
-     * @param serviceID
-     * @param roots
-     * @return
-     */
-    private Map<String, Object> buildResourceProviderProperties(String servicePID, long serviceID, String[] roots) {
-        Map<String, Object> resourceProviderProperties = new HashMap<String, Object>();
-        resourceProviderProperties.put(Constants.SERVICE_PID, servicePID);
-        resourceProviderProperties.put(Constants.SERVICE_ID, serviceID);
-        resourceProviderProperties.put(Constants.SERVICE_VENDOR, "Apache");
-        resourceProviderProperties.put(Constants.SERVICE_DESCRIPTION,
-            "Dummy Provider");
-        resourceProviderProperties.put(QueriableResourceProvider.LANGUAGES,
-                new String[] { FAKE_QUERY_LANGUAGE } );
-
-
-        resourceProviderProperties.put(ResourceProvider.ROOTS, roots);
-        return resourceProviderProperties;
-    }
-
     /**
      * build a properties for a resource resolver bundle.
      * @return
@@ -479,21 +440,6 @@ public class MockedResourceResolverImplT
     }
 
     /**
-     * Test getResource for a resource provided by a factory provider.
-     * @throws LoginException
-     */
-    @Test
-    public void testGetFactoryResource() throws LoginException {
-        ResourceResolver resourceResolver = resourceResolverFactory.getResourceResolver(null);
-        Assert.assertNotNull(resourceResolver);
-
-        Resource factoryResource = buildResource("/factory/test", EMPTY_RESOURCE_LIST, resourceResolver, factoryResourceProvider);
-        Resource resource = resourceResolver.getResource("/factory/test");
-        Assert.assertEquals(factoryResource, resource);
-    }
-
-
-    /**
      * Basic test of mapping functionality, at the moment needs more
      * configuration in the virtual /etc/map.
      *
@@ -502,21 +448,21 @@ public class MockedResourceResolverImplT
     @Test
     public void testMapping() throws LoginException {
         ResourceResolver resourceResolver = resourceResolverFactory.getResourceResolver(null);
-        buildResource("/factory/test", EMPTY_RESOURCE_LIST, resourceResolver, factoryResourceProvider);
+        buildResource("/single/test", EMPTY_RESOURCE_LIST, resourceResolver, resourceProvider);
         HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
         Mockito.when(request.getScheme()).thenReturn("http");
         Mockito.when(request.getServerPort()).thenReturn(80);
         Mockito.when(request.getServerName()).thenReturn("localhost");
-        String path = resourceResolver.map(request,"/factory/test?q=123123");
-        Assert.assertEquals("/factory/test?q=123123", path);
-        path = resourceResolver.map(request,"/factory/test");
-        Assert.assertEquals("/factory/test", path);
+        String path = resourceResolver.map(request,"/single/test?q=123123");
+        Assert.assertEquals("/single/test?q=123123", path);
+        path = resourceResolver.map(request,"/single/test");
+        Assert.assertEquals("/single/test", path);
 
         // test path mapping without a request.
-        path = resourceResolver.map("/factory/test");
-        Assert.assertEquals("/factory/test", path);
+        path = resourceResolver.map("/single/test");
+        Assert.assertEquals("/single/test", path);
 
-        buildResource("/content", EMPTY_RESOURCE_LIST, resourceResolver, factoryResourceProvider);
+        buildResource("/content", EMPTY_RESOURCE_LIST, resourceResolver, resourceProvider);
         path = resourceResolver.map("/content.html");
         Assert.assertEquals("/content.html", path);
 
@@ -597,10 +543,13 @@ public class MockedResourceResolverImplT
         Assert.assertEquals(5,i);
     }
 
+    @SuppressWarnings("unchecked")
     @Test
     public void testQueryResources() throws LoginException {
         final int n = 3;
-        Mockito.when(queriableResourceProviderA.queryResources(Mockito.any(ResourceResolver.class), Mockito.any(String.class), Mockito.any(String.class)))
+        String[] languages = new String[] {FAKE_QUERY_LANGUAGE};
+        Mockito.when(queryProvider.getSupportedLanguages(Mockito.any(ResolveContext.class))).thenReturn(languages);
+        Mockito.when(queryProvider.queryResources(Mockito.any(ResolveContext.class), Mockito.any(String.class), Mockito.any(String.class)))
         .thenReturn(buildValueMapCollection(n, "A_").iterator());
 
         final ResourceResolver rr = resourceResolverFactory.getResourceResolver(null);

Added: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ProviderHandlerTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ProviderHandlerTest.java?rev=1709747&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ProviderHandlerTest.java (added)
+++ sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ProviderHandlerTest.java Wed Oct 21 08:23:09 2015
@@ -0,0 +1,80 @@
+/*
+ * 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.resourceresolver.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import static org.apache.sling.resourceresolver.impl.MockedResourceResolverImplTest.createRPHandler;
+
+import java.util.Arrays;
+
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.NonExistingResource;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceMetadata;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.resourceresolver.impl.CommonResourceResolverFactoryImpl;
+import org.apache.sling.resourceresolver.impl.ResourceResolverFactoryActivator;
+import org.apache.sling.resourceresolver.impl.ResourceResolverImpl;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderHandler;
+import org.apache.sling.spi.resource.provider.ResolveContext;
+import org.apache.sling.spi.resource.provider.ResourceProvider;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+public class ProviderHandlerTest {
+
+    @SuppressWarnings("unchecked")
+    @Test public void testServletRegistrationAndSyntheticResources() throws LoginException {
+        final String servletpath = "/libs/a/b/GET.servlet";
+        final Resource servletResource = Mockito.mock(Resource.class);
+        Mockito.when(servletResource.getResourceMetadata()).then(new Answer<ResourceMetadata>() {
+            @Override
+            public ResourceMetadata answer(InvocationOnMock invocation) throws Throwable {
+                return new ResourceMetadata();
+            }
+        });
+
+        final ResourceProvider<?> leaveProvider = Mockito.mock(ResourceProvider.class);
+        Mockito.when(leaveProvider.getResource(Mockito.any(ResolveContext.class), Mockito.eq(servletpath), Mockito.any(Resource.class))).thenReturn(servletResource);
+        ResourceProviderHandler h = createRPHandler(leaveProvider, "my-pid", 0, servletpath);
+        ResourceResolver resolver = new ResourceResolverImpl(new CommonResourceResolverFactoryImpl(new ResourceResolverFactoryActivator()), false, null, Arrays.asList(h));
+        
+        final Resource parent = resolver.getResource(ResourceUtil.getParent(servletpath));
+        assertNotNull("Parent must be available", parent);
+        assertTrue("Resource should be synthetic", ResourceUtil.isSyntheticResource(parent));
+
+        final Resource servlet = resolver.getResource(servletpath);
+        assertNotNull("Servlet resource must not be null", servlet);
+        assertEquals(servletResource, servlet);
+
+        assertNotNull(resolver.getResource("/libs"));
+
+        // now check when doing a resolve()
+        assertTrue(resolver.resolve("/libs") instanceof NonExistingResource);
+        assertTrue(resolver.resolve(ResourceUtil.getParent(servletpath)) instanceof NonExistingResource);
+        assertNotNull(resolver.resolve(servletpath));
+        resolver.close();
+    }
+}

Modified: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceDecoratorReturnsNullTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceDecoratorReturnsNullTest.java?rev=1709747&r1=1709746&r2=1709747&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceDecoratorReturnsNullTest.java (original)
+++ sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceDecoratorReturnsNullTest.java Wed Oct 21 08:23:09 2015
@@ -29,6 +29,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 
+import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.Resource;
 import org.junit.Before;
 import org.junit.Test;
@@ -66,7 +67,7 @@ public class ResourceDecoratorReturnsNul
     }
     
     @Before
-    public void setup() {
+    public void setup() throws LoginException {
         super.setup();
         pathsThatReturnNull.add("/tmp/D");
         pathsThatReturnNull.add("/var/two");

Modified: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceDecoratorTestBase.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceDecoratorTestBase.java?rev=1709747&r1=1709746&r2=1709747&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceDecoratorTestBase.java (original)
+++ sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceDecoratorTestBase.java Wed Oct 21 08:23:09 2015
@@ -22,27 +22,26 @@ import static org.junit.Assert.assertEqu
 import static org.junit.Assert.assertNotNull;
 
 import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 
 import javax.servlet.http.HttpServletRequest;
 
+import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.NonExistingResource;
-import org.apache.sling.api.resource.QueriableResourceProvider;
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceDecorator;
 import org.apache.sling.api.resource.ResourceMetadata;
-import org.apache.sling.api.resource.ResourceProvider;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ValueMap;
 import org.apache.sling.resourceresolver.impl.helper.ResourceDecoratorTracker;
-import org.apache.sling.resourceresolver.impl.helper.ResourceResolverContext;
-import org.apache.sling.resourceresolver.impl.tree.RootResourceProviderEntry;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderHandler;
+import org.apache.sling.spi.resource.provider.JCRQueryProvider;
+import org.apache.sling.spi.resource.provider.ResolveContext;
+import org.apache.sling.spi.resource.provider.ResourceProvider;
 import org.junit.Before;
 import org.mockito.Mockito;
-import org.osgi.framework.Constants;
 
 /** Base class for tests that involve ResourceDecorators */
 public abstract class ResourceDecoratorTestBase {
@@ -53,7 +52,7 @@ public abstract class ResourceDecoratorT
     protected abstract Resource wrapResourceForTest(Resource resource);
 
     @Before
-    public void setup() {
+    public void setup() throws LoginException {
         final ResourceDecorator d = new ResourceDecorator() {
             public Resource decorate(Resource resource) {
                 return ResourceDecoratorTestBase.this.wrapResourceForTest(resource);
@@ -68,20 +67,44 @@ public abstract class ResourceDecoratorT
         final ResourceDecoratorTracker t = new ResourceDecoratorTracker();
         t.bindResourceDecorator(d, null);
 
-        final ResourceProvider provider = new QueriableResourceProvider() {
+        final ResourceProvider<?> provider = new ResourceProvider<Object>() {
 
-            public Resource getResource(ResourceResolver resourceResolver, HttpServletRequest request, String path) {
-                return getResource(null, path);
-            }
+            @Override
+            public JCRQueryProvider<Object> getJCRQueryProvider() {
+                return new JCRQueryProvider<Object>() {
 
-            public Resource getResource(ResourceResolver resourceResolver, String path) {
+                    @Override
+                    public String[] getSupportedLanguages(ResolveContext<Object> ctx) {
+                        return new String[] { QUERY_LANGUAGE };
+                    }
+
+                    @Override
+                    public Iterator<Resource> findResources(ResolveContext<Object> ctx, String query, String language) {
+                        final List<Resource> found = new ArrayList<Resource>();
+                        found.add(mockResource("/tmp/C"));
+                        found.add(mockResource("/tmp/D"));
+                        found.add(mockResource("/var/one"));
+                        found.add(mockResource("/var/two"));
+                        return found.iterator();
+                    }
+
+                    @Override
+                    public Iterator<ValueMap> queryResources(ResolveContext<Object> ctx, String query, String language) {
+                        return null;
+                    }
+                };
+            }
+            
+            @Override
+            public Resource getResource(ResolveContext<Object> ctx, String path, Resource parent) {
                 if(path.equals("/") || path.startsWith("/tmp") || path.startsWith("/var")) {
                     return mockResource(path);
                 }
                 return null;
             }
 
-            public Iterator<Resource> listChildren(Resource parent) {
+            @Override
+            public Iterator<Resource> listChildren(ResolveContext<Object> ctx, Resource parent) {
                 final List<Resource> children = new ArrayList<Resource>();
                 if("/".equals(parent.getPath())) {
                     children.add(mockResource("/tmp"));
@@ -99,40 +122,18 @@ public abstract class ResourceDecoratorT
                 return children.iterator();
             }
 
-            public Iterator<ValueMap> queryResources(ResourceResolver resolver, String query, String language) {
-                return null;
-            }
-
-            public Iterator<Resource> findResources(ResourceResolver resolver, String query, String language) {
-                final List<Resource> found = new ArrayList<Resource>();
-                found.add(mockResource("/tmp/C"));
-                found.add(mockResource("/tmp/D"));
-                found.add(mockResource("/var/one"));
-                found.add(mockResource("/var/two"));
-                return found.iterator();
-            }
-
         };
 
-        final RootResourceProviderEntry rrp = new RootResourceProviderEntry();
-        final Map<String, Object> props = new HashMap<String, Object>();
-        props.put(Constants.SERVICE_ID, System.currentTimeMillis());
-        props.put(ResourceProvider.ROOTS, "/");
-        props.put(QueriableResourceProvider.LANGUAGES, QUERY_LANGUAGE);
-        rrp.bindResourceProvider(provider, props);
-
-        final CommonResourceResolverFactoryImpl  crf = new CommonResourceResolverFactoryImpl(new ResourceResolverFactoryActivator()) {
+        ResourceResolverFactoryActivator activator = new ResourceResolverFactoryActivator();
+        final CommonResourceResolverFactoryImpl crf = new CommonResourceResolverFactoryImpl(activator) {
             @Override
             public ResourceDecoratorTracker getResourceDecoratorTracker() {
                 return t;
             }
-
-            @Override
-            public RootResourceProviderEntry getRootProviderEntry() {
-                return rrp;
-            }
         };
-        resolver = new ResourceResolverImpl(crf, new ResourceResolverContext(false, null, new ResourceAccessSecurityTracker()));
+
+        List<ResourceProviderHandler> list = Arrays.asList(MockedResourceResolverImplTest.createRPHandler(provider, "A-provider", 0L, "/"));
+        resolver = new ResourceResolverImpl(crf, false, null, list);
     }
 
     protected void assertExistent(Resource r, boolean existent) {

Added: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceProviderEntryTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceProviderEntryTest.java?rev=1709747&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceProviderEntryTest.java (added)
+++ sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceProviderEntryTest.java Wed Oct 21 08:23:09 2015
@@ -0,0 +1,290 @@
+/*
+ * 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.resourceresolver.impl;
+
+import static org.apache.sling.resourceresolver.impl.MockedResourceResolverImplTest.createRPHandler;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sling.api.resource.AbstractResource;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceMetadata;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.SyntheticResource;
+import org.apache.sling.resourceresolver.impl.CommonResourceResolverFactoryImpl;
+import org.apache.sling.resourceresolver.impl.ResourceResolverFactoryActivator;
+import org.apache.sling.resourceresolver.impl.ResourceResolverImpl;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderHandler;
+import org.apache.sling.spi.resource.provider.ResolveContext;
+import org.apache.sling.spi.resource.provider.ResourceProvider;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.osgi.framework.Constants;
+
+@SuppressWarnings("unchecked")
+public class ResourceProviderEntryTest {
+
+    private List<ResourceProviderHandler> providers = new ArrayList<ResourceProviderHandler>();
+
+    private ResourceResolver providersBasedResolver;
+
+    private ResourceResolver mockedRootResolver;
+
+    @Before public void setUp() throws Exception {
+        this.mockedRootResolver = Mockito.mock(ResourceResolver.class);
+        this.providersBasedResolver = null;
+        this.providers.clear();
+        final ResourceProvider<?> rootProvider = Mockito.mock(ResourceProvider.class);
+        Mockito.when(rootProvider.getResource(Mockito.any(ResolveContext.class), Mockito.anyString(), Mockito.any(Resource.class))).thenReturn(new TestResource(this.mockedRootResolver));
+        providers.add(createRPHandler(rootProvider, "rp0", 0, "/"));
+    }
+
+    @Test public void testRootProvider() throws LoginException {
+        assertNull(getResource("relpath"));
+        assertEqualsResolver(this.mockedRootResolver, getResource("/"));
+        assertEqualsResolver(this.mockedRootResolver, getResource("/rootel"));
+        assertEqualsResolver(this.mockedRootResolver, getResource("/rootel/child"));
+        assertEqualsResolver(this.mockedRootResolver, getResource("/apps/sling/sample/html.js"));
+        assertEqualsResolver(this.mockedRootResolver, getResource("/apps/sling/microsling/html.js"));
+    }
+
+    @Test public void testAdd1Provider() throws LoginException {
+        String firstPath = "/rootel";
+        final ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+        final ResourceProvider<?> first = Mockito.mock(ResourceProvider.class);
+        Mockito.when(first.getResource(Mockito.any(ResolveContext.class), Mockito.startsWith(firstPath), Mockito.any(Resource.class))).thenReturn(new TestResource(resolver));
+
+        providers.add(createRPHandler(first, "rp1", 1, "/rootel"));
+        this.providersBasedResolver = null;
+
+        assertEqualsResolver(this.mockedRootResolver, getResource("/"));
+        assertEqualsResolver(resolver, getResource("/rootel"));
+        assertEqualsResolver(resolver, getResource("/rootel/html.js"));
+        assertEqualsResolver(resolver, getResource("/rootel/child"));
+        assertEqualsResolver(resolver, getResource("/rootel/child/html.js"));
+        assertEqualsResolver(this.mockedRootResolver, getResource("/apps/sling/sample/html.js"));
+        assertEqualsResolver(this.mockedRootResolver, getResource("/apps/sling/microsling/html.js"));
+    }
+
+    @Test public void testAdd3Providers() throws LoginException {
+        String firstPath = "/rootel";
+        String secondPath = firstPath + "/child";
+        String thirdPath = "/apps/sling/sample";
+
+        final ResourceResolver firstResolver = Mockito.mock(ResourceResolver.class);
+        final ResourceProvider<?> first = Mockito.mock(ResourceProvider.class);
+        Mockito.when(first.getResource(Mockito.any(ResolveContext.class), Mockito.startsWith(firstPath), Mockito.any(Resource.class))).thenReturn(new TestResource(firstResolver));
+        final ResourceResolver secondResolver = Mockito.mock(ResourceResolver.class);
+        final ResourceProvider<?> second = Mockito.mock(ResourceProvider.class);
+        Mockito.when(second.getResource(Mockito.any(ResolveContext.class), Mockito.startsWith(secondPath), Mockito.any(Resource.class))).thenReturn(new TestResource(secondResolver));
+        final ResourceResolver thirdResolver = Mockito.mock(ResourceResolver.class);
+        final ResourceProvider<?> third = Mockito.mock(ResourceProvider.class);
+        Mockito.when(third.getResource(Mockito.any(ResolveContext.class), Mockito.startsWith(thirdPath), Mockito.any(Resource.class))).thenReturn(new TestResource(thirdResolver));
+
+        providers.add(createRPHandler(first, "rp1", 1, firstPath));
+        providers.add(createRPHandler(second, "rp2", 2, secondPath));
+        providers.add(createRPHandler(third, "rp3", 3, thirdPath));
+        this.providersBasedResolver = null;
+
+        assertEqualsResolver(this.mockedRootResolver, getResource("/"));
+        assertEqualsResolver(firstResolver, getResource("/rootel"));
+        assertEqualsResolver(firstResolver, getResource("/rootel/html.js"));
+        assertEqualsResolver(secondResolver, getResource("/rootel/child"));
+        assertEqualsResolver(secondResolver, getResource("/rootel/child/html.js"));
+        assertEqualsResolver(thirdResolver, getResource("/apps/sling/sample/html.js"));
+        assertEqualsResolver(this.mockedRootResolver, getResource("/apps/sling/microsling/html.js"));
+    }
+
+    @Test public void testAdd3ProvidersReverse() throws LoginException {
+        String firstPath = "/rootel";
+        String secondPath = firstPath + "/child";
+        String thirdPath = "/apps/sling/sample";
+
+        final ResourceResolver firstResolver = Mockito.mock(ResourceResolver.class);
+        final ResourceProvider<?> first = Mockito.mock(ResourceProvider.class);
+        Mockito.when(first.getResource(Mockito.any(ResolveContext.class), Mockito.startsWith(firstPath), Mockito.any(Resource.class))).thenReturn(new TestResource(firstResolver));
+        final ResourceResolver secondResolver = Mockito.mock(ResourceResolver.class);
+        final ResourceProvider<?> second = Mockito.mock(ResourceProvider.class);
+        Mockito.when(second.getResource(Mockito.any(ResolveContext.class), Mockito.startsWith(secondPath), Mockito.any(Resource.class))).thenReturn(new TestResource(secondResolver));
+        final ResourceResolver thirdResolver = Mockito.mock(ResourceResolver.class);
+        final ResourceProvider<?> third = Mockito.mock(ResourceProvider.class);
+        Mockito.when(third.getResource(Mockito.any(ResolveContext.class), Mockito.startsWith(thirdPath), Mockito.any(Resource.class))).thenReturn(new TestResource(thirdResolver));
+
+        providers.add(createRPHandler(first, "rp1", 1, firstPath));
+        providers.add(createRPHandler(second, "rp2", 2, secondPath));
+        providers.add(createRPHandler(third, "rp3", 3, thirdPath));
+        this.providersBasedResolver = null;
+
+        assertEqualsResolver(this.mockedRootResolver, getResource("/"));
+        assertEqualsResolver(firstResolver, getResource("/rootel"));
+        assertEqualsResolver(firstResolver, getResource("/rootel/html.js"));
+        assertEqualsResolver(secondResolver, getResource("/rootel/child"));
+        assertEqualsResolver(secondResolver, getResource("/rootel/child/html.js"));
+        assertEqualsResolver(thirdResolver, getResource("/apps/sling/sample/html.js"));
+        assertEqualsResolver(this.mockedRootResolver, getResource("/apps/sling/microsling/html.js"));
+    }
+
+    @Test public void testRemoveProviders() throws LoginException {
+        String firstPath = "/rootel";
+        String thirdPath = "/apps/sling/sample";
+        String secondPath = firstPath + "/child";
+
+        final ResourceResolver firstResolver = Mockito.mock(ResourceResolver.class);
+        final ResourceProvider<?> first = Mockito.mock(ResourceProvider.class);
+        Mockito.when(first.getResource(Mockito.any(ResolveContext.class), Mockito.startsWith(firstPath), Mockito.any(Resource.class))).thenReturn(new TestResource(firstResolver));
+        final ResourceResolver secondResolver = Mockito.mock(ResourceResolver.class);
+        final ResourceProvider<?> second = Mockito.mock(ResourceProvider.class);
+        Mockito.when(second.getResource(Mockito.any(ResolveContext.class), Mockito.startsWith(secondPath), Mockito.any(Resource.class))).thenReturn(new TestResource(secondResolver));
+        final ResourceResolver thirdResolver = Mockito.mock(ResourceResolver.class);
+        final ResourceProvider<?> third = Mockito.mock(ResourceProvider.class);
+        Mockito.when(third.getResource(Mockito.any(ResolveContext.class), Mockito.startsWith(thirdPath), Mockito.any(Resource.class))).thenReturn(new TestResource(thirdResolver));
+
+        final Map<String, Object> firstProps = new HashMap<String, Object>();
+        firstProps.put(Constants.SERVICE_ID, (long)1);
+        final Map<String, Object> secondProps = new HashMap<String, Object>();
+        secondProps.put(Constants.SERVICE_ID, (long)2);
+        final Map<String, Object> thirdProps = new HashMap<String, Object>();
+        thirdProps.put(Constants.SERVICE_ID, (long)3);
+
+        ResourceProviderHandler firstH = createRPHandler(first, "rp1", 1, firstPath);
+        providers.add(firstH);
+        providers.add(createRPHandler(second, "rp2", 2, secondPath));
+        providers.add(createRPHandler(third, "rp3", 3, thirdPath));
+        this.providersBasedResolver = null;
+
+        assertEqualsResolver(this.mockedRootResolver, getResource("/"));
+        assertEqualsResolver(firstResolver, getResource("/rootel/html.js"));
+        assertEqualsResolver(secondResolver, getResource("/rootel/child/html.js"));
+
+        providers.remove(firstH);
+        this.providersBasedResolver = null;
+
+        assertEqualsResolver(this.mockedRootResolver, getResource("/"));
+        assertEqualsResolver(this.mockedRootResolver, getResource("/rootel/sddsf/sdfsdf/html.js"));
+        assertEqualsResolver(this.mockedRootResolver, getResource("/rootel/html.js"));
+        assertEqualsResolver(secondResolver, getResource("/rootel/child/html.js"));
+
+        providers.add(firstH);
+        this.providersBasedResolver = null;
+
+        assertEqualsResolver(this.mockedRootResolver, getResource("/"));
+        assertEqualsResolver(firstResolver, getResource("/rootel/html.js"));
+        assertEqualsResolver(secondResolver, getResource("/rootel/child/html.js"));
+    }
+
+    @Test public void testRemoveTheOnlyProvider() throws LoginException {
+        long counter = 1;
+
+        providers.clear();
+        for(String path : new String[] { "/foo", "/", "/foo/bar" }) {
+            final ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+            final ResourceProvider<?> p = Mockito.mock(ResourceProvider.class);
+            Mockito.when(p.getResource(Mockito.any(ResolveContext.class), Mockito.startsWith(path), Mockito.any(Resource.class))).thenReturn(new TestResource(resolver));
+
+            ++counter;
+
+            ResourceProviderHandler h = createRPHandler(p, "rp"+counter, counter, path);
+            providers.add(h);
+            this.providersBasedResolver = null;
+            {
+                final Resource r = getResource(path);
+                assertEqualsResolver(resolver, r);
+                assertFalse(r instanceof SyntheticResource);
+            }
+
+            providers.remove(h);
+            this.providersBasedResolver = null;
+            {
+                final Resource r = getResource(path);
+                // If our provider is indeed gone, we should get one of the following conditions
+                if(r == null) {
+                    //fine
+                } else if(!p.equals(r.getResourceResolver())) {
+                    //fine
+                } else {
+                    fail("Expecting inactive provider after removing it for " + path);
+                }
+            }
+        }
+    }
+
+    private void assertEqualsResolver(final ResourceResolver resolver, final Resource res) {
+        assertEquals(resolver, res.getResourceResolver());
+    }
+
+    private Resource getResource(String path) throws LoginException {
+        return getResolver().getResource(path);
+    }
+    
+    private ResourceResolver getResolver() throws LoginException {
+        if (providersBasedResolver == null) {
+            providersBasedResolver = new ResourceResolverImpl(new CommonResourceResolverFactoryImpl(new ResourceResolverFactoryActivator()), false, null, providers);
+        }
+        return providersBasedResolver;
+    }
+
+    private static class TestResource extends AbstractResource {
+
+        private final ResourceResolver resourceResolver;
+
+        public TestResource(ResourceResolver resourceResolver) {
+            this.resourceResolver = resourceResolver;
+        }
+
+        public String getPath() {
+            return null;
+        }
+
+        public ResourceMetadata getResourceMetadata() {
+            return new ResourceMetadata();
+        }
+
+        public ResourceResolver getResourceResolver() {
+            return resourceResolver;
+        }
+
+        public String getResourceType() {
+            return null;
+        }
+
+        public String getResourceSuperType() {
+            return null;
+        }
+
+        @Override
+        public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+            return null;
+        }
+
+		@Override
+        public boolean hasChildren() {
+			return false;
+		}
+    }
+}

Modified: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryTest.java?rev=1709747&r1=1709746&r2=1709747&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryTest.java (original)
+++ sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryTest.java Wed Oct 21 08:23:09 2015
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertNot
 import static org.junit.Assert.assertNull;
 
 import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderTracker;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -31,7 +32,9 @@ public class ResourceResolverFactoryTest
     private CommonResourceResolverFactoryImpl commonFactory;
 
     @Before public void setup() {
-        commonFactory = new CommonResourceResolverFactoryImpl(new ResourceResolverFactoryActivator());
+        ResourceResolverFactoryActivator activator = new ResourceResolverFactoryActivator();
+        activator.resourceProviderTracker = new ResourceProviderTracker();
+        commonFactory = new CommonResourceResolverFactoryImpl(activator);
     }
 
     @Test public void testSingleThreadLocal() throws Exception {

Modified: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java?rev=1709747&r1=1709746&r2=1709747&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java (original)
+++ sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java Wed Oct 21 08:23:09 2015
@@ -18,6 +18,8 @@
  */
 package org.apache.sling.resourceresolver.impl;
 
+import static java.util.Arrays.asList;
+import static org.apache.sling.resourceresolver.impl.MockedResourceResolverImplTest.createRPHandler;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -26,7 +28,6 @@ import static org.junit.Assert.assertTru
 import static org.junit.Assert.fail;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -38,11 +39,16 @@ import javax.servlet.http.HttpServletReq
 
 import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.NonExistingResource;
+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.ResourceResolverFactory;
 import org.apache.sling.api.resource.SyntheticResource;
-import org.apache.sling.resourceresolver.impl.helper.ResourceResolverContext;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderHandler;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderStorage;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderTracker;
+import org.apache.sling.spi.resource.provider.ResolveContext;
+import org.apache.sling.spi.resource.provider.ResourceProvider;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
@@ -55,15 +61,37 @@ public class ResourceResolverImplTest {
     private ResourceResolver resResolver;
 
     private ResourceResolverFactoryImpl resFac;
+    
+    private ResourceProviderTracker resourceProviderTracker;
 
-    @Before public void setup() {
-        commonFactory = new CommonResourceResolverFactoryImpl(new ResourceResolverFactoryActivator());
+    @Before public void setup() throws LoginException {
+        ResourceProvider<?> rp = new ResourceProvider<Object>() {
+
+            @Override
+            public Resource getResource(ResolveContext<Object> ctx, String path, Resource parent) {
+                return null;
+            }
+
+            @Override
+            public Iterator<Resource> listChildren(ResolveContext<Object> ctx, Resource parent) {
+                return null;
+            }
+        };
+
+        List<ResourceProviderHandler> handlers = asList(createRPHandler(rp, "rp1", 0, "/"));
+        resourceProviderTracker = Mockito.mock(ResourceProviderTracker.class);
+        ResourceProviderStorage storage = new ResourceProviderStorage(handlers);
+        Mockito.when(resourceProviderTracker.getResourceProviderStorage()).thenReturn(storage);
+        ResourceResolverFactoryActivator activator = new ResourceResolverFactoryActivator();
+        activator.resourceProviderTracker = resourceProviderTracker;
+        commonFactory = new CommonResourceResolverFactoryImpl(activator);
         resFac = new ResourceResolverFactoryImpl(commonFactory, /* TODO: using Bundle */ null, null);
-        resResolver = new ResourceResolverImpl(commonFactory, new ResourceResolverContext(false, null, new ResourceAccessSecurityTracker()));
+        resResolver = resFac.getAdministrativeResourceResolver(null);
     }
 
+    @SuppressWarnings("deprecation")
     @Test public void testClose() throws Exception {
-        final ResourceResolver rr = new ResourceResolverImpl(commonFactory, new ResourceResolverContext(false, null, new ResourceAccessSecurityTracker()));
+        final ResourceResolver rr = new ResourceResolverImpl(commonFactory, false, null, resourceProviderTracker.getResourceProviderStorage());
         assertTrue(rr.isLive());
         rr.close();
         assertFalse(rr.isLive());
@@ -174,8 +202,7 @@ public class ResourceResolverImplTest {
         ResourceResolverFactoryActivator rrfa = Mockito.spy(new ResourceResolverFactoryActivator());
         Whitebox.setInternalState(rrfa, "logResourceResolverClosing", true);
         CommonResourceResolverFactoryImpl crrfi = new CommonResourceResolverFactoryImpl(rrfa);
-        final ResourceResolver rr = new ResourceResolverImpl(crrfi, new ResourceResolverContext(false, null, new
-            ResourceAccessSecurityTracker()));
+        final ResourceResolver rr = new ResourceResolverImpl(crrfi, false, null, resourceProviderTracker.getResourceProviderStorage());
         assertTrue(rr.isLive());
         rr.close();
         assertFalse(rr.isLive());
@@ -453,12 +480,12 @@ public class ResourceResolverImplTest {
         try {
             this.resResolver.create(r, "a", null);
             fail("This should be unsupported.");
-        } catch (final UnsupportedOperationException uoe) {
+        } catch (final PersistenceException uoe) {
             // correct
         }
     }
 
-    @Test public void test_getResourceSuperType() {
+    @Test public void test_getResourceSuperType() throws LoginException {
         // the resource resolver
         final List<ResourceResolver> resolvers = new ArrayList<ResourceResolver>();
         final PathBasedResourceResolverImpl resolver = new PathBasedResourceResolverImpl(
@@ -470,9 +497,7 @@ public class ResourceResolverImplTest {
                             throws LoginException {
                         return resolvers.get(0);
                     }
-
-                },
-                new ResourceResolverContext(false, null, new ResourceAccessSecurityTracker()));
+                }, resourceProviderTracker);
         resolvers.add(resolver);
 
         // the resources to test
@@ -491,7 +516,7 @@ public class ResourceResolverImplTest {
         assertNull(resolver.getParentResourceType(r2.getResourceType()));
     }
 
-    @Test public void test_isA() {
+    @Test public void test_isA() throws LoginException {
         final Resource typeResource = Mockito.mock(Resource.class);
         Mockito.when(typeResource.getResourceType()).thenReturn("x:y");
         Mockito.when(typeResource.getResourceSuperType()).thenReturn("t:c");
@@ -506,9 +531,7 @@ public class ResourceResolverImplTest {
                             throws LoginException {
                         return resolvers.get(0);
                     }
-
-                },
-                new ResourceResolverContext(false, null, new ResourceAccessSecurityTracker()));
+                }, resourceProviderTracker);
         resolvers.add(resolver);
         final Resource r = new SyntheticResource(resolver, "/a", "a:b") {
             @Override
@@ -530,9 +553,8 @@ public class ResourceResolverImplTest {
 
         private final Map<String, Resource> resources = new HashMap<String, Resource>();
 
-        public PathBasedResourceResolverImpl(
-                CommonResourceResolverFactoryImpl factory, ResourceResolverContext ctx) {
-            super(factory, ctx);
+        public PathBasedResourceResolverImpl(CommonResourceResolverFactoryImpl factory, ResourceProviderTracker resourceProviderTracker) throws LoginException {
+            super(factory, false, null, resourceProviderTracker.getResourceProviderStorage());
         }
 
         public void setResource(final String path, final Resource r) {