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

svn commit: r1710978 - in /sling/trunk/bundles/resourceresolver/src: main/java/org/apache/sling/resourceresolver/impl/ main/java/org/apache/sling/resourceresolver/impl/providers/stateful/ main/java/org/apache/sling/resourceresolver/impl/providers/tree/...

Author: cziegeler
Date: Wed Oct 28 10:23:48 2015
New Revision: 1710978

URL: http://svn.apache.org/viewvc?rev=1710978&view=rev
Log:
SLING-5201 : Improve resource provider resolving

Modified:
    sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/BasicResolveContext.java
    sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/CommonResourceResolverFactoryImpl.java
    sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java
    sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/AuthenticatedResourceProvider.java
    sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/CombinedResourceProvider.java
    sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/EmptyResourceProvider.java
    sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/ResourceProviderAuthenticator.java
    sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/SecureResourceProvider.java
    sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/StatefulResourceProvider.java
    sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/StatefulResourceProviderWrapper.java
    sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/PathTree.java
    sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/MockedResourceResolverImplTest.java

Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/BasicResolveContext.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/BasicResolveContext.java?rev=1710978&r1=1710977&r2=1710978&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/BasicResolveContext.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/BasicResolveContext.java Wed Oct 28 10:23:48 2015
@@ -18,31 +18,47 @@
  */
 package org.apache.sling.resourceresolver.impl;
 
+import org.apache.sling.api.SlingException;
+import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderHandler;
+import org.apache.sling.resourceresolver.impl.providers.ResourceProviderStorage;
+import org.apache.sling.resourceresolver.impl.providers.stateful.CombinedResourceProvider;
+import org.apache.sling.resourceresolver.impl.providers.stateful.StatefulResourceProvider;
 import org.apache.sling.spi.resource.provider.ResolverContext;
 import org.apache.sling.spi.resource.provider.ResourceProvider;
 
+// TODO - we should move this to the providers.stateful package
 public class BasicResolveContext<T> implements ResolverContext<T> {
 
+    private final String parentPath;
+
     private final ResourceResolver resourceResolver;
 
     private final T providerState;
 
-    private final ResolverContext<Object> parentResolveContext;
+    private final CombinedResourceProvider combinedProvider;
+
+    private volatile boolean parentLookupDone = false;
+
+    private volatile ResourceProvider parentProvider;
 
-    private final ResourceProvider<Object> parentResourceProvider;
+    private volatile ResolverContext<Object> parentResolveContext;
 
     public BasicResolveContext(ResourceResolver resourceResolver,
-            T providerState, ResourceProvider<Object> parentResourceProvider, ResolverContext<Object> parentResolveContext) {
+            T providerState,
+            String parentPath,
+            CombinedResourceProvider combinedProvider) {
         this.resourceResolver = resourceResolver;
+        this.parentPath = parentPath;
         this.providerState = providerState;
-        this.parentResolveContext = parentResolveContext;
-        this.parentResourceProvider = parentResourceProvider;
+        this.combinedProvider = combinedProvider;
     }
 
     public BasicResolveContext(ResourceResolver resourceResolver,
-            T providerState) {
-        this(resourceResolver, providerState, null, null);
+            T providerState, String parentPath) {
+        this(resourceResolver, providerState, parentPath, null);
     }
 
     @Override
@@ -57,12 +73,44 @@ public class BasicResolveContext<T> impl
 
     @Override
     public ResolverContext<?> getParentResolveContext() {
+        this.getParentResourceProvider();
         return parentResolveContext;
     }
 
     @Override
     public ResourceProvider<?> getParentResourceProvider() {
-        return parentResourceProvider;
+        if ( ! parentLookupDone ) {
+            synchronized ( this ) {
+                if ( this.parentPath != null ) {
+                    final ResourceProviderStorage storage = this.combinedProvider.getResourceProviderStorage();
+                    String path = this.parentPath;
+                    while ( path != null && this.parentProvider != null ) {
+                        final ResourceProviderHandler handler = storage.getTree().getBestMatchingNode(this.parentPath);
+                        if ( handler != null ) {
+                            try {
+                                final StatefulResourceProvider srp = this.combinedProvider.getStatefulResourceProvider(handler);
+                                if ( srp != null ) {
+                                    this.parentProvider = srp.getResourceProvider();
+                                    this.parentResolveContext = srp.getContext();
+                                }
+                            } catch ( final LoginException se) {
+                                // skip this, try next
+                                this.parentProvider = null;
+                            } catch ( final SlingException se) {
+                                // TODO we should rather catch LoginException from getStatefulResourceProvider
+                            }
+                            if ( this.parentProvider == null ) {
+                                path = ResourceUtil.getParent(path);
+                            }
+                        } else {
+                            path = null;
+                        }
+                    }
+                }
+                parentLookupDone = true;
+            }
+        }
+        return this.parentProvider;
     }
 
 }

Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/CommonResourceResolverFactoryImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/CommonResourceResolverFactoryImpl.java?rev=1710978&r1=1710977&r2=1710978&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/CommonResourceResolverFactoryImpl.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/CommonResourceResolverFactoryImpl.java Wed Oct 28 10:23:48 2015
@@ -351,7 +351,7 @@ public class CommonResourceResolverFacto
     public long getMaxCachedVanityPathEntries() {
         return this.activator.getMaxCachedVanityPathEntries();
     }
-    
+
     @Override
     public boolean isMaxCachedVanityPathEntriesStartup() {
         return this.activator.isMaxCachedVanityPathEntriesStartup();
@@ -405,6 +405,10 @@ public class CommonResourceResolverFacto
         return logResourceResolverClosing;
     }
 
+    public ResourceProviderTracker getResourceProviderTracker() {
+        return activator.getResourceProviderTracker();
+    }
+
     /**
      * Extension of a weak reference to be able to get the context object
      * that is used for cleaning up.
@@ -424,8 +428,4 @@ public class CommonResourceResolverFacto
             this.context.close();
         }
     }
-
-    public ResourceProviderTracker getResourceProviderTracker() {
-        return activator.getResourceProviderTracker();
-    }
 }
\ No newline at end of file

Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java?rev=1710978&r1=1710977&r2=1710978&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java Wed Oct 28 10:23:48 2015
@@ -143,8 +143,9 @@ public class ResourceResolverImpl extend
 
     private CombinedResourceProvider createProvider(ResourceProviderStorage storage) throws LoginException {
         final ResourceProviderAuthenticator authenticator = new ResourceProviderAuthenticator(this, authenticationInfo, this.factory.getResourceAccessSecurityTracker());
-        authenticator.authenticateAll(storage.getAuthRequiredHandlers());
-        return new CombinedResourceProvider(storage, this, authenticator);
+        final CombinedResourceProvider provider = new CombinedResourceProvider(storage, this, authenticator);
+        authenticator.authenticateAll(storage.getAuthRequiredHandlers(), provider);
+        return provider;
     }
 
     /**

Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/AuthenticatedResourceProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/AuthenticatedResourceProvider.java?rev=1710978&r1=1710977&r2=1710978&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/AuthenticatedResourceProvider.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/AuthenticatedResourceProvider.java Wed Oct 28 10:23:48 2015
@@ -21,7 +21,6 @@ package org.apache.sling.resourceresolve
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -31,6 +30,7 @@ import org.apache.sling.api.resource.Per
 import org.apache.sling.api.resource.Resource;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.api.resource.ResourceUtil;
 import org.apache.sling.api.resource.query.Query;
 import org.apache.sling.api.resource.query.QueryInstructions;
 import org.apache.sling.api.resource.runtime.dto.AuthType;
@@ -75,13 +75,19 @@ public class AuthenticatedResourceProvid
 
     private JCRQueryProvider<Object> cachedJcrQueryProvider;
 
+    private final CombinedResourceProvider combinedProvider;
+
     @SuppressWarnings("unchecked")
-    public AuthenticatedResourceProvider(ResourceProvider<?> rp, ResourceProviderInfo info, ResourceResolver resolver,
-            Map<String, Object> authInfo) throws LoginException {
+    public AuthenticatedResourceProvider(ResourceProvider<?> rp,
+            ResourceProviderInfo info,
+            ResourceResolver resolver,
+            Map<String, Object> authInfo,
+            CombinedResourceProvider combinedProvider) throws LoginException {
         this.rp = (ResourceProvider<Object>) rp;
         this.info = info;
         this.authInfo = authInfo;
         this.resolver = resolver;
+        this.combinedProvider = combinedProvider;
         if (info.getAuthType() == AuthType.required) {
             authenticate();
         }
@@ -95,38 +101,19 @@ public class AuthenticatedResourceProvid
         return contextData;
     }
 
-    private ResolverContext<Object> getBasicContext() throws LoginException {
-        if (cachedContext != null) {
-            return cachedContext;
-        }
-        return cachedContext = getContext(null);
-    }
-
     @Override
     public ResolverContext<Object> getContext() throws LoginException {
-        return getBasicContext();
-    }
-
-    private ResolverContext<Object> getContext(List<StatefulResourceProvider> parentProviders) throws LoginException {
-        ResourceProvider<Object> parentProvider = null;
-        ResolverContext<Object> parentContext = null;
-        try {
-            if (parentProviders != null && !parentProviders.isEmpty()) {
-                StatefulResourceProvider statefulParentProvider = parentProviders.get(0);
-                parentProvider = statefulParentProvider.getResourceProvider();
-                parentContext = statefulParentProvider.getContext();
-            }
-        } catch (LoginException e) {
-            logger.warn("Can't authenticate the parent resource provider", e);
+        if (cachedContext == null) {
+            cachedContext = new BasicResolveContext<Object>(resolver, authenticate(), ResourceUtil.getParent(info.getPath()), this.combinedProvider);
         }
-        return new BasicResolveContext<Object>(resolver, authenticate(), parentProvider, parentContext);
+        return cachedContext;
     }
 
     @Override
     public void logout() {
         if (authenticated) {
             try {
-                rp.logout(getBasicContext().getProviderState());
+                rp.logout(getContext().getProviderState());
             } catch (LoginException e) {
                 logger.error("Can't create context", e);
             }
@@ -138,7 +125,7 @@ public class AuthenticatedResourceProvid
     @Override
     public void refresh() {
         try {
-            rp.refresh(getBasicContext());
+            rp.refresh(getContext());
         } catch (LoginException e) {
             logger.error("Can't create context", e);
         }
@@ -147,7 +134,7 @@ public class AuthenticatedResourceProvid
     @Override
     public boolean isLive() {
         try {
-            return rp.isLive(getBasicContext());
+            return rp.isLive(getContext());
         } catch (LoginException e) {
             logger.error("Can't create context", e);
             return false;
@@ -155,9 +142,9 @@ public class AuthenticatedResourceProvid
     }
 
     @Override
-    public Resource getParent(Resource child, List<StatefulResourceProvider> parentProviders) {
+    public Resource getParent(Resource child) {
         try {
-            return rp.getParent(getContext(parentProviders), child);
+            return rp.getParent(getContext(), child);
         } catch (LoginException e) {
             logger.error("Can't create context", e);
             return null;
@@ -165,7 +152,7 @@ public class AuthenticatedResourceProvid
     }
 
     @Override
-    public Resource getResource(String path, Resource parent, final Map<String, String> parameters, boolean isResolve, List<StatefulResourceProvider> parentProviders) {
+    public Resource getResource(String path, Resource parent, final Map<String, String> parameters, boolean isResolve) {
         ResourceContext resourceContext = ResourceContext.EMPTY_CONTEXT;
         if ( parameters != null ) {
             resourceContext = new ResourceContext() {
@@ -178,7 +165,7 @@ public class AuthenticatedResourceProvid
             };
         }
         try {
-            return rp.getResource(getContext(parentProviders), path, resourceContext, parent);
+            return rp.getResource(getContext(), path, resourceContext, parent);
         } catch (LoginException e) {
             logger.error("Can't create context", e);
             return null;
@@ -187,9 +174,9 @@ public class AuthenticatedResourceProvid
     }
 
     @Override
-    public Iterator<Resource> listChildren(Resource parent, List<StatefulResourceProvider> parentProviders) {
+    public Iterator<Resource> listChildren(Resource parent) {
         try {
-            return rp.listChildren(getContext(parentProviders), parent);
+            return rp.listChildren(getContext(), parent);
         } catch (LoginException e) {
             logger.error("Can't create context", e);
             return null;
@@ -201,7 +188,7 @@ public class AuthenticatedResourceProvid
         Set<String> attributeNames = new LinkedHashSet<String>();
         Collection<String> rpAttributeNames = null;
         try {
-            rpAttributeNames = rp.getAttributeNames(getBasicContext());
+            rpAttributeNames = rp.getAttributeNames(getContext());
         } catch (LoginException e) {
             logger.error("Can't create context", e);
         }
@@ -222,7 +209,7 @@ public class AuthenticatedResourceProvid
         }
         Object attribute = null;
         try {
-            attribute = rp.getAttribute(getBasicContext(), name);
+            attribute = rp.getAttribute(getContext(), name);
         } catch (LoginException e) {
             logger.error("Can't create context", e);
         }
@@ -233,9 +220,9 @@ public class AuthenticatedResourceProvid
     }
 
     @Override
-    public Resource create(String path, Map<String, Object> properties, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
+    public Resource create(String path, Map<String, Object> properties) throws PersistenceException {
         try {
-            return rp.create(getContext(parentProviders), path, properties);
+            return rp.create(getContext(), path, properties);
         } catch (LoginException e) {
             logger.error("Can't create context", e);
             return null;
@@ -243,9 +230,9 @@ public class AuthenticatedResourceProvid
     }
 
     @Override
-    public void delete(Resource resource, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
+    public void delete(Resource resource) throws PersistenceException {
         try {
-            rp.delete(getContext(parentProviders), resource);
+            rp.delete(getContext(), resource);
         } catch (LoginException e) {
             logger.error("Can't create context", e);
         }
@@ -254,7 +241,7 @@ public class AuthenticatedResourceProvid
     @Override
     public void revert() {
         try {
-            rp.revert(getBasicContext());
+            rp.revert(getContext());
         } catch (LoginException e) {
             logger.error("Can't create context", e);
         }
@@ -263,7 +250,7 @@ public class AuthenticatedResourceProvid
     @Override
     public void commit() throws PersistenceException {
         try {
-            rp.commit(getBasicContext());
+            rp.commit(getContext());
         } catch (LoginException e) {
             logger.error("Can't create context", e);
         }
@@ -272,7 +259,7 @@ public class AuthenticatedResourceProvid
     @Override
     public boolean hasChanges() {
         try {
-            return rp.hasChanges(getBasicContext());
+            return rp.hasChanges(getContext());
         } catch (LoginException e) {
             logger.error("Can't create context", e);
             return false;
@@ -300,7 +287,7 @@ public class AuthenticatedResourceProvid
             return null;
         }
         try {
-            return provider.find(getBasicContext(), q, qi);
+            return provider.find(getContext(), q, qi);
         } catch (LoginException e) {
             logger.error("Can't create context", e);
             return null;
@@ -314,7 +301,7 @@ public class AuthenticatedResourceProvid
             return null;
         }
         try {
-            return jcrQueryProvider.getSupportedLanguages(getBasicContext());
+            return jcrQueryProvider.getSupportedLanguages(getContext());
         } catch (LoginException e) {
             logger.error("Can't create context", e);
             return ArrayUtils.EMPTY_STRING_ARRAY;
@@ -328,7 +315,7 @@ public class AuthenticatedResourceProvid
             return null;
         }
         try {
-            return jcrQueryProvider.findResources(getBasicContext(), query, language);
+            return jcrQueryProvider.findResources(getContext(), query, language);
         } catch (LoginException e) {
             logger.error("Can't create context", e);
             return null;
@@ -343,7 +330,7 @@ public class AuthenticatedResourceProvid
             return null;
         }
         try {
-            return (Iterator) jcrQueryProvider.queryResources(getBasicContext(), query, language);
+            return (Iterator) jcrQueryProvider.queryResources(getContext(), query, language);
         } catch (LoginException e) {
             logger.error("Can't create context", e);
             return null;
@@ -353,7 +340,7 @@ public class AuthenticatedResourceProvid
     @Override
     public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
         try {
-            return rp.adaptTo(getBasicContext(), type);
+            return rp.adaptTo(getContext(), type);
         } catch (LoginException e) {
             logger.error("Can't create context", e);
             return null;
@@ -361,9 +348,9 @@ public class AuthenticatedResourceProvid
     }
 
     @Override
-    public boolean copy(String srcAbsPath, String destAbsPath, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
+    public boolean copy(String srcAbsPath, String destAbsPath) throws PersistenceException {
         try {
-            return rp.copy(getContext(parentProviders), srcAbsPath, destAbsPath);
+            return rp.copy(getContext(), srcAbsPath, destAbsPath);
         } catch (LoginException e) {
             logger.error("Can't create context", e);
             return false;
@@ -371,9 +358,9 @@ public class AuthenticatedResourceProvid
     }
 
     @Override
-    public boolean move(String srcAbsPath, String destAbsPath, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
+    public boolean move(String srcAbsPath, String destAbsPath) throws PersistenceException {
         try {
-            return rp.move(getContext(parentProviders), srcAbsPath, destAbsPath);
+            return rp.move(getContext(), srcAbsPath, destAbsPath);
         } catch (LoginException e) {
             logger.error("Can't create context", e);
             return false;

Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/CombinedResourceProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/CombinedResourceProvider.java?rev=1710978&r1=1710977&r2=1710978&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/CombinedResourceProvider.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/CombinedResourceProvider.java Wed Oct 28 10:23:48 2015
@@ -48,6 +48,7 @@ import org.apache.sling.api.resource.Syn
 import org.apache.sling.api.resource.query.Query;
 import org.apache.sling.api.resource.query.QueryInstructions;
 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.tree.Node;
 import org.apache.sling.spi.resource.provider.QueryResult;
@@ -92,7 +93,7 @@ public class CombinedResourceProvider {
      * Refreshes all providers.
      */
     public void refresh() {
-        for (StatefulResourceProvider p : authenticator.getAll(storage.getRefreshableHandlers())) {
+        for (StatefulResourceProvider p : authenticator.getAll(storage.getRefreshableHandlers(), this)) {
             p.refresh();
         }
     }
@@ -112,15 +113,15 @@ public class CombinedResourceProvider {
     /**
      * Returns parent from the most appropriate resource provider accepting the
      * given children.
-     * 
+     *
      * In some cases the {@link SyntheticResource} can be returned if no
      * resource provider returns parent for this child. See
      * {@link #getResource(String, Resource, Map, boolean)} for more details
      */
     public Resource getParent(Resource child) {
-        String path = child.getPath();
-        List<StatefulResourceProvider> matching = getMatchingProviders(path);
-        Resource parentCandidate = head(matching).getParent(child, tail(matching));
+        final String path = child.getPath();
+        final StatefulResourceProvider provider = getBestMatchingProvider(path);
+        Resource parentCandidate = provider.getParent(child);
         if (parentCandidate != null) {
             return parentCandidate;
         }
@@ -152,8 +153,8 @@ public class CombinedResourceProvider {
         }
 
         try {
-            List<StatefulResourceProvider> matching = getMatchingProviders(path);
-            Resource resourceCandidate = head(matching).getResource(path, parent, parameters, isResolve, tail(matching));
+            final StatefulResourceProvider provider = this.getBestMatchingProvider(path);
+            final Resource resourceCandidate = provider.getResource(path, parent, parameters, isResolve);
             if (resourceCandidate != null) {
                 return resourceCandidate;
             }
@@ -193,14 +194,14 @@ public class CombinedResourceProvider {
     @SuppressWarnings("unchecked")
     public Iterator<Resource> listChildren(final Resource parent) {
         List<StatefulResourceProvider> matching = getMatchingProviders(parent.getPath());
-        Iterator<Resource> realChildren = head(matching).listChildren(parent, tail(matching));
+        Iterator<Resource> realChildren = head(matching).listChildren(parent);
         Iterator<Resource> syntheticChildren = getSyntheticChildren(parent).iterator();
         Iterator<Resource> allChildren;
         if (realChildren == null) {
             allChildren = syntheticChildren;
         } else {
             allChildren = new UniqueIterator(chainedIterator(realChildren, syntheticChildren));
-        } 
+        }
         return transformedIterator(allChildren, new Transformer() {
             @Override
             public Object transform(Object input) {
@@ -224,8 +225,8 @@ public class CombinedResourceProvider {
             final Resource child;
             if (handler == null) {
                 child = new SyntheticResource(resolver, childPath, RESOURCE_TYPE_SYNTHETIC);
-            } else { 
-                child = authenticator.getStateful(handler).getResource(childPath, parent, null, false, null);
+            } else {
+                child = authenticator.getStateful(handler, this).getResource(childPath, parent, null, false);
             }
             if (child != null) {
                 children.add(child);
@@ -239,7 +240,7 @@ public class CombinedResourceProvider {
      */
     public Collection<String> getAttributeNames() {
         final Set<String> names = new LinkedHashSet<String>();
-        for (StatefulResourceProvider p : authenticator.getAll(storage.getAttributableHandlers())) {
+        for (StatefulResourceProvider p : authenticator.getAll(storage.getAttributableHandlers(), this)) {
             Collection<String> newNames = p.getAttributeNames();
             if (newNames != null) {
                 names.addAll(newNames);
@@ -254,7 +255,7 @@ public class CombinedResourceProvider {
      * the providers.
      */
     public Object getAttribute(String name) {
-        for (StatefulResourceProvider p : authenticator.getAll(storage.getAttributableHandlers())) {
+        for (StatefulResourceProvider p : authenticator.getAll(storage.getAttributableHandlers(), this)) {
             Object attribute = p.getAttribute(name);
             if (attribute != null) {
                 return attribute;
@@ -276,7 +277,7 @@ public class CombinedResourceProvider {
      */
     public Resource create(String path, Map<String, Object> properties) throws PersistenceException {
         List<StatefulResourceProvider> matching = getMatchingModifiableProviders(path);
-        Resource creationResultResource = head(matching).create(path, properties, tail(matching));
+        Resource creationResultResource = head(matching).create(path, properties);
         if (creationResultResource != null) {
             return creationResultResource;
         }
@@ -303,10 +304,10 @@ public class CombinedResourceProvider {
 
         // Give all viable handlers a chance to delete the resource
         for (StatefulResourceProvider p : getMatchingModifiableProviders(path)) {
-            Resource providerResource = p.getResource(path, null, parameters, false, null);
+            Resource providerResource = p.getResource(path, null, parameters, false);
             if (providerResource != null) {
                 anyProviderAttempted = true;
-                p.delete(providerResource, null);
+                p.delete(providerResource);
             }
         }
         // If none of the viable handlers could delete the resource or if the
@@ -358,7 +359,7 @@ public class CombinedResourceProvider {
      */
     public String[] getSupportedLanguages() {
         Set<String> supportedLanguages = new LinkedHashSet<String>();
-        for (StatefulResourceProvider p : authenticator.getAll(storage.getJcrQuerableHandlers())) {
+        for (StatefulResourceProvider p : authenticator.getAll(storage.getJcrQuerableHandlers(), this)) {
             supportedLanguages.addAll(Arrays.asList(p.getSupportedLanguages()));
         }
         return supportedLanguages.toArray(new String[supportedLanguages.size()]);
@@ -378,7 +379,7 @@ public class CombinedResourceProvider {
 
     private List<StatefulResourceProvider> getQuerableProviders(String language) {
         List<StatefulResourceProvider> querableProviders = new ArrayList<StatefulResourceProvider>();
-        for (StatefulResourceProvider p : authenticator.getAll(storage.getJcrQuerableHandlers())) {
+        for (StatefulResourceProvider p : authenticator.getAll(storage.getJcrQuerableHandlers(), this)) {
             if (ArrayUtils.contains(p.getSupportedLanguages(), language)) {
                 querableProviders.add(p);
             }
@@ -404,7 +405,7 @@ public class CombinedResourceProvider {
      */
     @SuppressWarnings("unchecked")
     public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
-        for (StatefulResourceProvider p : authenticator.getAll(storage.getAdaptableHandlers())) {
+        for (StatefulResourceProvider p : authenticator.getAll(storage.getAdaptableHandlers(), this)) {
             final Object adaptee = p.adaptTo(type);
             if (adaptee != null) {
                 return (AdapterType) adaptee;
@@ -423,7 +424,7 @@ public class CombinedResourceProvider {
         List<StatefulResourceProvider> dstProviders = getMatchingModifiableProviders(destAbsPath);
         @SuppressWarnings("unchecked")
         List<StatefulResourceProvider> intersection = ListUtils.intersection(srcProviders, dstProviders);
-        return head(intersection).copy(srcAbsPath, destAbsPath, tail(intersection));
+        return head(intersection).copy(srcAbsPath, destAbsPath);
     }
 
     /**
@@ -436,7 +437,28 @@ public class CombinedResourceProvider {
         List<StatefulResourceProvider> dstProviders = getMatchingModifiableProviders(destAbsPath);
         @SuppressWarnings("unchecked")
         List<StatefulResourceProvider> intersection = ListUtils.intersection(srcProviders, dstProviders);
-        return head(intersection).move(srcAbsPath, destAbsPath, tail(intersection));
+        return head(intersection).move(srcAbsPath, destAbsPath);
+    }
+
+    public ResourceProviderStorage getResourceProviderStorage() {
+        return this.storage;
+    }
+
+    public StatefulResourceProvider getStatefulResourceProvider(final ResourceProviderHandler handler) {
+        if ( handler != null ) {
+            return authenticator.getStateful(handler, this);
+        }
+        return null;
+    }
+
+    /**
+     * @param path
+     * @return
+     * @throws SlingException
+     */
+    private StatefulResourceProvider getBestMatchingProvider(final String path) {
+        final ResourceProviderHandler handler = storage.getTree().getBestMatchingNode(path);
+        return handler == null ? EmptyResourceProvider.SINGLETON : authenticator.getStateful(handler, this);
     }
 
     private List<StatefulResourceProvider> getMatchingProviders(String path) {
@@ -444,7 +466,7 @@ public class CombinedResourceProvider {
         StatefulResourceProvider[] matching = new StatefulResourceProvider[handlers.size()];
         int i = matching.length - 1;
         for (ResourceProviderHandler h : handlers) {
-            matching[i--] = authenticator.getStateful(h); // reverse order
+            matching[i--] = authenticator.getStateful(h, this);
         }
         return Arrays.asList(matching);
     }
@@ -454,7 +476,7 @@ public class CombinedResourceProvider {
         List<StatefulResourceProvider> matching = new ArrayList<StatefulResourceProvider>(handlers.size());
         for (ResourceProviderHandler h : handlers) {
             if (h.getInfo().getModifiable()) {
-                matching.add(authenticator.getStateful(h));
+                matching.add(authenticator.getStateful(h, this));
             }
         }
         Collections.reverse(matching);
@@ -496,7 +518,7 @@ public class CombinedResourceProvider {
         @Override
         public Iterator<Resource> iterator() {
             @SuppressWarnings("unchecked")
-            Iterator<Iterator<Resource>> iterators = IteratorUtils.transformedIterator(authenticator.getAll(storage.getNativeQuerableHandlers()).iterator(),
+            Iterator<Iterator<Resource>> iterators = IteratorUtils.transformedIterator(authenticator.getAll(storage.getNativeQuerableHandlers(), CombinedResourceProvider.this).iterator(),
                     new Transformer() {
                         @Override
                         public Object transform(Object input) {
@@ -536,7 +558,7 @@ public class CombinedResourceProvider {
             }
         }
     }
-    
+
     /**
      * This iterator removes duplicated Resource entries. Regular resources
      * overrides the synthetic ones.

Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/EmptyResourceProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/EmptyResourceProvider.java?rev=1710978&r1=1710977&r2=1710978&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/EmptyResourceProvider.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/EmptyResourceProvider.java Wed Oct 28 10:23:48 2015
@@ -20,7 +20,6 @@ package org.apache.sling.resourceresolve
 
 import java.util.Collection;
 import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
 
 import org.apache.sling.api.resource.PersistenceException;
@@ -34,6 +33,8 @@ import org.apache.sling.spi.resource.pro
 
 public class EmptyResourceProvider implements StatefulResourceProvider {
 
+    public static final StatefulResourceProvider SINGLETON = new EmptyResourceProvider();
+
     @Override
     public ResourceResolver getResourceResolver() {
         return null;
@@ -53,18 +54,17 @@ public class EmptyResourceProvider imple
     }
 
     @Override
-    public Resource getParent(Resource child, List<StatefulResourceProvider> parentProviders) {
+    public Resource getParent(Resource child) {
         return null;
     }
 
     @Override
-    public Resource getResource(String path, Resource parent, Map<String, String> parameters, boolean isResolve,
-            List<StatefulResourceProvider> parentProviders) {
+    public Resource getResource(String path, Resource parent, Map<String, String> parameters, boolean isResolve) {
         return null;
     }
 
     @Override
-    public Iterator<Resource> listChildren(Resource parent, List<StatefulResourceProvider> parentProviders) {
+    public Iterator<Resource> listChildren(Resource parent) {
         return null;
     }
 
@@ -79,13 +79,13 @@ public class EmptyResourceProvider imple
     }
 
     @Override
-    public Resource create(String path, Map<String, Object> properties, List<StatefulResourceProvider> parentProviders)
+    public Resource create(String path, Map<String, Object> properties)
             throws PersistenceException {
         return null;
     }
 
     @Override
-    public void delete(Resource resource, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
+    public void delete(Resource resource) throws PersistenceException {
     }
 
     @Override
@@ -127,13 +127,13 @@ public class EmptyResourceProvider imple
     }
 
     @Override
-    public boolean copy(String srcAbsPath, String destAbsPath, List<StatefulResourceProvider> parentProviders)
+    public boolean copy(String srcAbsPath, String destAbsPath)
             throws PersistenceException {
         return false;
     }
 
     @Override
-    public boolean move(String srcAbsPath, String destAbsPath, List<StatefulResourceProvider> parentProviders)
+    public boolean move(String srcAbsPath, String destAbsPath)
             throws PersistenceException {
         return false;
     }

Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/ResourceProviderAuthenticator.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/ResourceProviderAuthenticator.java?rev=1710978&r1=1710977&r2=1710978&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/ResourceProviderAuthenticator.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/ResourceProviderAuthenticator.java Wed Oct 28 10:23:48 2015
@@ -62,16 +62,17 @@ public class ResourceProviderAuthenticat
         this.securityTracker = securityTracker;
     }
 
-    public void authenticateAll(List<ResourceProviderHandler> handlers) throws LoginException {
+    public void authenticateAll(List<ResourceProviderHandler> handlers, CombinedResourceProvider combinedProvider) throws LoginException {
         for (ResourceProviderHandler h : handlers) {
-            authenticate(h);
+            authenticate(h, combinedProvider);
         }
     }
 
-    private StatefulResourceProvider authenticate(ResourceProviderHandler handler) throws LoginException {
+    private StatefulResourceProvider authenticate(final ResourceProviderHandler handler,
+            CombinedResourceProvider combinedProvider) throws LoginException {
         StatefulResourceProvider rp = stateful.get(handler);
         if (rp == null) {
-            rp = createStateful(handler);
+            rp = createStateful(handler, combinedProvider);
             if (rp == null) {
                 return null;
             }
@@ -86,9 +87,9 @@ public class ResourceProviderAuthenticat
         return rp;
     }
 
-    public StatefulResourceProvider getStateful(ResourceProviderHandler handler) {
+    public StatefulResourceProvider getStateful(ResourceProviderHandler handler, CombinedResourceProvider combinedProvider) {
         try {
-            return authenticate(handler);
+            return authenticate(handler, combinedProvider);
         } catch (LoginException e) {
             throw new SlingException("Can't authenticate provider", e);
         }
@@ -102,22 +103,24 @@ public class ResourceProviderAuthenticat
         return authenticatedModifiable;
     }
 
-    public Collection<StatefulResourceProvider> getAll(List<ResourceProviderHandler> handlers) {
+    public Collection<StatefulResourceProvider> getAll(List<ResourceProviderHandler> handlers,
+            CombinedResourceProvider combinedProvider) {
         List<StatefulResourceProvider> result = new ArrayList<StatefulResourceProvider>(handlers.size());
         for (ResourceProviderHandler h : handlers) {
-            result.add(getStateful(h));
+            result.add(getStateful(h, combinedProvider));
         }
         return result;
     }
 
-    private StatefulResourceProvider createStateful(ResourceProviderHandler handler) throws LoginException {
+    private StatefulResourceProvider createStateful(ResourceProviderHandler handler,
+            CombinedResourceProvider combinedProvider) throws LoginException {
         ResourceProvider<?> rp = handler.getResourceProvider();
         if (rp == null) {
             logger.warn("Empty resource provider for {}", handler);
             return null;
         }
         StatefulResourceProvider authenticated;
-        authenticated = new AuthenticatedResourceProvider(rp, handler.getInfo(), resolver, authInfo);
+        authenticated = new AuthenticatedResourceProvider(rp, handler.getInfo(), resolver, authInfo, combinedProvider);
         if (handler.getInfo().getUseResourceAccessSecurity()) {
             authenticated = new SecureResourceProvider(authenticated, securityTracker);
         }

Modified: 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=1710978&r1=1710977&r2=1710978&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/SecureResourceProvider.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/SecureResourceProvider.java Wed Oct 28 10:23:48 2015
@@ -19,7 +19,6 @@
 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;
@@ -49,28 +48,28 @@ public class SecureResourceProvider exte
     }
 
     @Override
-    public Resource create(final String path, Map<String, Object> properties, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
+    public Resource create(final String path, Map<String, Object> properties) throws PersistenceException {
         if (isAllowed(new SecurityTest() {
             @Override
             public boolean isAllowed(ResourceAccessSecurity security) {
                 return security.canCreate(path, getResourceResolver());
             }
         })) {
-            return rp.create(path, properties, parentProviders);
+            return rp.create(path, properties);
         } else {
             return null;
         }
     }
 
     @Override
-    public void delete(final Resource resource, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
+    public void delete(final Resource resource) throws PersistenceException {
         if (isAllowed(new SecurityTest() {
             @Override
             public boolean isAllowed(ResourceAccessSecurity security) {
                 return security.canDelete(resource);
             }
         })) {
-            rp.delete(resource, parentProviders);
+            rp.delete(resource);
         }
     }
 

Modified: 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=1710978&r1=1710977&r2=1710978&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/StatefulResourceProvider.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/StatefulResourceProvider.java Wed Oct 28 10:23:48 2015
@@ -20,7 +20,6 @@ package org.apache.sling.resourceresolve
 
 import java.util.Collection;
 import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
 
 import javax.annotation.CheckForNull;
@@ -68,21 +67,20 @@ public interface StatefulResourceProvide
      * @see ResourceProvider#getParent(org.apache.sling.spi.resource.provider.ResolveContext, Resource)
      */
     @CheckForNull
-    Resource getParent(final @Nonnull Resource child, final List<StatefulResourceProvider> parentProviders);
+    Resource getParent(final @Nonnull Resource child);
 
     /**
      * @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);
+            final Map<String, String> parameters, final boolean isResolve);
 
     /**
      * @see ResourceProvider#listChildren(org.apache.sling.spi.resource.provider.ResolveContext, Resource)
      */
     @CheckForNull
-    Iterator<Resource> listChildren(final @Nonnull Resource parent, final List<StatefulResourceProvider> parentProviders);
+    Iterator<Resource> listChildren(final @Nonnull Resource parent);
 
     /**
      * @see ResourceProvider#getAttributeNames(org.apache.sling.spi.resource.provider.ResolveContext)
@@ -97,12 +95,12 @@ public interface StatefulResourceProvide
     /**
      * @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;
+    Resource create(final String path, final Map<String, Object> properties) 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;
+    void delete(final @Nonnull Resource resource) throws PersistenceException;
 
     /**
      * @see ResourceProvider#revert(org.apache.sling.spi.resource.provider.ResolveContext)
@@ -152,12 +150,12 @@ public interface StatefulResourceProvide
     /**
      * @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;
+    boolean copy(final String srcAbsPath, final String destAbsPath) 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;
+    boolean move(final String srcAbsPath, final String destAbsPath) throws PersistenceException;
 
     /**
      * @return Wrapped ResourceProvider

Modified: 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=1710978&r1=1710977&r2=1710978&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/StatefulResourceProviderWrapper.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/stateful/StatefulResourceProviderWrapper.java Wed Oct 28 10:23:48 2015
@@ -20,7 +20,6 @@ package org.apache.sling.resourceresolve
 
 import java.util.Collection;
 import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
 
 import org.apache.sling.api.resource.LoginException;
@@ -57,18 +56,18 @@ public class StatefulResourceProviderWra
     }
 
     @Override
-    public Resource getParent(Resource child, List<StatefulResourceProvider> parentProviders) {
-        return rp.getParent(child, parentProviders);
+    public Resource getParent(Resource child) {
+        return rp.getParent(child);
     }
 
     @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);
+    public Resource getResource(String path, Resource parent, Map<String, String> parameters, boolean isResolve) {
+        return rp.getResource(path, parent, parameters, isResolve);
     }
 
     @Override
-    public Iterator<Resource> listChildren(Resource parent, List<StatefulResourceProvider> parentProviders) {
-        return rp.listChildren(parent, parentProviders);
+    public Iterator<Resource> listChildren(Resource parent) {
+        return rp.listChildren(parent);
     }
 
     @Override
@@ -82,13 +81,13 @@ public class StatefulResourceProviderWra
     }
 
     @Override
-    public Resource create(String path, Map<String, Object> properties, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
-        return rp.create(path, properties, parentProviders);
+    public Resource create(String path, Map<String, Object> properties) throws PersistenceException {
+        return rp.create(path, properties);
     }
 
     @Override
-    public void delete(Resource resource, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
-        rp.delete(resource, parentProviders);
+    public void delete(Resource resource) throws PersistenceException {
+        rp.delete(resource);
     }
 
     @Override
@@ -132,13 +131,13 @@ public class StatefulResourceProviderWra
     }
 
     @Override
-    public boolean copy(String srcAbsPath, String destAbsPath, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
-        return rp.copy(srcAbsPath, destAbsPath, parentProviders);
+    public boolean copy(String srcAbsPath, String destAbsPath) throws PersistenceException {
+        return rp.copy(srcAbsPath, destAbsPath);
     }
 
     @Override
-    public boolean move(String srcAbsPath, String destAbsPath, List<StatefulResourceProvider> parentProviders) throws PersistenceException {
-        return rp.move(srcAbsPath, destAbsPath, parentProviders);
+    public boolean move(String srcAbsPath, String destAbsPath) throws PersistenceException {
+        return rp.move(srcAbsPath, destAbsPath);
     }
 
     @Override

Modified: 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=1710978&r1=1710977&r2=1710978&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/PathTree.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/providers/tree/PathTree.java Wed Oct 28 10:23:48 2015
@@ -48,6 +48,29 @@ public class PathTree<T extends Pathable
         node.setValue(value);
     }
 
+    public T getBestMatchingNode(final String path) {
+        if (path == null || path.isEmpty() || path.charAt(0) != '/') {
+            return null;
+        }
+
+        T result = 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) {
+                    result = node.getValue();
+                }
+            }
+        }
+        return result;
+    }
+
     public List<T> getMatchingNodes(String path) {
         if (path == null || path.isEmpty() || path.charAt(0) != '/') {
             return Collections.emptyList();

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=1710978&r1=1710977&r2=1710978&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 28 10:23:48 2015
@@ -64,8 +64,6 @@ 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;
 
 /**
  * This tests the ResourceResolver using mocks. The Unit test is in addition to
@@ -215,14 +213,9 @@ public class MockedResourceResolverImplT
         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) {
-            }
-        });
+        final ResourceProviderHandler handler = new ResourceProviderHandler(bc, info);
+        handler.activate();
+        return handler;
     }
 
     @SuppressWarnings("unchecked")