incubator-sling-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cziege...@apache.org
Subject svn commit: r1350169 [4/5] - in /sling/trunk/bundles/resourceresolver/src: main/java/org/apache/sling/resourceresolver/impl/ main/java/org/apache/sling/resourceresolver/impl/console/ main/java/org/apache/sling/resourceresolver/impl/helper/ main/java/or...
Date Thu, 14 Jun 2012 09:52:09 GMT
Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderEntry.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderEntry.java?rev=1350169&r1=1350168&r2=1350169&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderEntry.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderEntry.java Thu Jun 14 09:52:08 2012
@@ -16,13 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.jcr.resource.internal.helper;
+package org.apache.sling.resourceresolver.impl.tree;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -32,6 +31,7 @@ import org.apache.sling.api.resource.Res
 import org.apache.sling.api.resource.ResourceProvider;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.SyntheticResource;
+import org.apache.sling.resourceresolver.impl.helper.ResourceResolverContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -39,16 +39,9 @@ import org.slf4j.LoggerFactory;
  * The <code>ResourceProviderEntry</code> class represents a node in the tree of
  * resource providers spanned by the root paths of the provider resources.
  * <p>
- * This class is comparable to itself to help keep the child entries list sorted
- * by their prefix.
+ * This class is comparable to itself to help keep the child entries list sorted by their prefix.
  */
-public class ResourceProviderEntry implements
-        Comparable<ResourceProviderEntry> {
-
-    /**
-     *
-     */
-    private static final long serialVersionUID = 7420631325909144862L;
+public class ResourceProviderEntry implements Comparable<ResourceProviderEntry> {
 
     private static Logger LOGGER = LoggerFactory.getLogger(ResourceProviderEntry.class);
 
@@ -64,7 +57,7 @@ public class ResourceProviderEntry imple
 
     // the resource provider kept in this entry supporting resources at and
     // below the path of this entry.
-    private WrappedResourceProvider[] providers = new WrappedResourceProvider[0];
+    private ProviderHandler[] providers = new ProviderHandler[0];
 
     private long ttime = 0L;
 
@@ -74,7 +67,7 @@ public class ResourceProviderEntry imple
 
     private long nreal = 0L;
 
-    private FastTreeMap storageMap = new FastTreeMap();
+    private final FastTreeMap storageMap = new FastTreeMap();
 
     private Collection<ResourceProviderEntry> storageMapValues = new ArrayList<ResourceProviderEntry>();
 
@@ -88,7 +81,7 @@ public class ResourceProviderEntry imple
      * @param providerList
      *            The resource provider to encapsulate by this entry.
      */
-    public ResourceProviderEntry(String path, ResourceProvider[] providerList) {
+    public ResourceProviderEntry(final String path, final ProviderHandler[] providerList) {
         if (path.endsWith("/")) {
             this.path = path.substring(0, path.length() - 1);
             this.prefix = path;
@@ -96,15 +89,11 @@ public class ResourceProviderEntry imple
             this.path = path;
             this.prefix = path + "/";
         }
-        if ( providerList != null ) {
-          providers = new WrappedResourceProvider[providerList.length];
-          for ( int i = 0; i < providerList.length; i++ ) {
-            if ( providerList[i] instanceof WrappedResourceProvider ) {
-              providers[i] = (WrappedResourceProvider) providerList[i];
-            } else {
-              providers[i] = new WrappedResourceProvider(providerList[i], null);
+        if (providerList != null) {
+            providers = new ProviderHandler[providerList.length];
+            for (int i = 0; i < providerList.length; i++) {
+                providers[i] = providerList[i];
             }
-          }
         }
 
         // this will consume slightly more memory but ensures read is fast.
@@ -112,14 +101,14 @@ public class ResourceProviderEntry imple
 
     }
 
-    String getPath() {
+    public String getPath() {
         return path;
     }
 
     /**
-     * Returns the resource provider contained in this entry
+     * Returns the resource providers contained in this entry
      */
-    public ResourceProvider[] getResourceProviders() {
+    public ProviderHandler[] getResourceProviders() {
         return providers;
     }
 
@@ -135,8 +124,8 @@ public class ResourceProviderEntry imple
      * @throws org.apache.sling.api.SlingException
      *             if an error occurrs trying to access an existing resource.
      */
-    public Resource getResource(ResourceResolver resourceResolver, String path) {
-        return getInternalResource(resourceResolver, path);
+    public Resource getResource(final ResourceResolverContext ctx, final ResourceResolver resourceResolver, final String path) {
+        return getInternalResource(ctx, resourceResolver, path);
     }
 
     /**
@@ -146,38 +135,36 @@ public class ResourceProviderEntry imple
      *         subtree below this entry. Otherwise <code>false</code> is
      *         returned.
      */
-    public boolean addResourceProvider(String prefix, ResourceProvider provider, Comparable<?> comparable) {
-        synchronized (this) {
-            String[] elements = split(prefix, '/');
-            List<ResourceProviderEntry> entryPath = new ArrayList<ResourceProviderEntry>();
-            entryPath.add(this); // add this the start so if the list is empty we have a position to add to
-            populateProviderPath(entryPath, elements);
-            for (int i = entryPath.size() - 1; i < elements.length; i++) {
-                String stubPrefix = elements[i];
-                ResourceProviderEntry rpe2 = new ResourceProviderEntry(
-                        stubPrefix, new ResourceProvider[0]);
-                entryPath.get(i).put(elements[i], rpe2);
-                entryPath.add(rpe2);
-            }
-            return entryPath.get(elements.length).addInternalProvider(new WrappedResourceProvider(provider, comparable));
-
+    public synchronized boolean addResourceProvider(final String prefix, final ProviderHandler provider) {
+        final String[] elements = split(prefix, '/');
+        final List<ResourceProviderEntry> entryPath = new ArrayList<ResourceProviderEntry>();
+        entryPath.add(this); // add this the start so if the list is empty
+        // we have a position to add to
+        populateProviderPath(entryPath, elements);
+        for (int i = entryPath.size() - 1; i < elements.length; i++) {
+            final String stubPrefix = elements[i];
+            final ResourceProviderEntry rpe2 = new ResourceProviderEntry(stubPrefix, new ProviderHandler[0]);
+            entryPath.get(i).put(stubPrefix, rpe2);
+            entryPath.add(rpe2);
         }
+        return entryPath.get(elements.length).addInternalProvider(provider);
     }
 
-
-    //------------------ Map methods, here so that we can delegate 2 maps together
+    // ------------------ Map methods, here so that we can delegate 2 maps
+    // together
     @SuppressWarnings("unchecked")
-    public void put(String key, ResourceProviderEntry value) {
-        storageMap.put(key,value);
-        // get a thread safe copy, the ArrayList constructor does a toArray which is thread safe.
+    public void put(final String key, final ResourceProviderEntry value) {
+        storageMap.put(key, value);
+        // get a thread safe copy, the ArrayList constructor does a toArray
+        // which is thread safe.
         storageMapValues = new ArrayList<ResourceProviderEntry>(storageMap.values());
     }
 
-    public boolean containsKey(String key) {
+    public boolean containsKey(final String key) {
         return storageMap.containsKey(key);
     }
 
-    public ResourceProviderEntry get(String key) {
+    public ResourceProviderEntry get(final String key) {
         return (ResourceProviderEntry) storageMap.get(key);
     }
 
@@ -185,23 +172,20 @@ public class ResourceProviderEntry imple
         return storageMapValues;
     }
 
-    public boolean removeResourceProvider(String prefix,
-            ResourceProvider resourceProvider, Comparable<?> comparable) {
-        synchronized (this) {
-            String[] elements = split(prefix, '/');
-            List<ResourceProviderEntry> entryPath = new ArrayList<ResourceProviderEntry>();
-            populateProviderPath(entryPath, elements);
-            if (entryPath.size() > 0 && entryPath.size() == elements.length) {
-                // the last element is a perfect match;
-                return entryPath.get(entryPath.size()-1).removeInternalProvider(new WrappedResourceProvider(resourceProvider, comparable));
-            }
-            return false;
+    public synchronized boolean removeResourceProvider(final String prefix, final ProviderHandler resourceProvider) {
+        final String[] elements = split(prefix, '/');
+        final List<ResourceProviderEntry> entryPath = new ArrayList<ResourceProviderEntry>();
+        populateProviderPath(entryPath, elements);
+        if (entryPath.size() > 0 && entryPath.size() == elements.length) {
+            // the last element is a perfect match;
+            return entryPath.get(entryPath.size() - 1).removeInternalProvider(resourceProvider);
         }
+        return false;
     }
 
     // ---------- Comparable<ResourceProviderEntry> interface ------------------
 
-    public int compareTo(ResourceProviderEntry o) {
+    public int compareTo(final ResourceProviderEntry o) {
         return prefix.compareTo(o.prefix);
     }
 
@@ -210,69 +194,46 @@ public class ResourceProviderEntry imple
     /**
      * Adds a list of providers to this entry.
      *
-     * @param provider
+     * No sync required as this is called by a sync method!
      */
-    private boolean addInternalProvider(WrappedResourceProvider provider) {
-        synchronized (providers) {
-            int before = providers.length;
-            Set<WrappedResourceProvider> set = new HashSet<WrappedResourceProvider>();
-            if (providers != null) {
-                set.addAll(Arrays.asList(providers));
-            }
-            LOGGER.debug("Adding provider {} at {} ",provider,path);
-            set.add(provider);
-            providers = conditionalSort(set);
-            return providers.length > before;
+    private boolean addInternalProvider(final ProviderHandler provider) {
+        final int before = providers.length;
+        final Set<ProviderHandler> set = new HashSet<ProviderHandler>();
+        if (providers != null) {
+            set.addAll(Arrays.asList(providers));
         }
-
+        LOGGER.debug("Adding provider {} at {} ", provider, path);
+        set.add(provider);
+        providers = conditionalSort(set);
+        return providers.length > before;
     }
 
     /**
-     * @param provider
-     * @return
+     * Remove a provider from the list of entries.
+     *
+     * No sync required as this is called by a sync method!
      */
-    private boolean removeInternalProvider(WrappedResourceProvider provider) {
-        synchronized (providers) {
-            int before = providers.length;
-            Set<WrappedResourceProvider> set = new HashSet<WrappedResourceProvider>();
-            if (providers != null) {
-                set.addAll(Arrays.asList(providers));
-            }
-            set.remove(provider);
-            providers = conditionalSort(set);
-            return providers.length < before;
+    private boolean removeInternalProvider(final ProviderHandler provider) {
+        final int before = providers.length;
+        final Set<ProviderHandler> set = new HashSet<ProviderHandler>();
+        if (providers != null) {
+            set.addAll(Arrays.asList(providers));
         }
+        set.remove(provider);
+        providers = conditionalSort(set);
+        return providers.length < before;
     }
 
     /**
-     * @param set
-     * @return
+     * Return a sorted array of handlers.
      */
-    private WrappedResourceProvider[] conditionalSort(Set<WrappedResourceProvider> set) {
-
-        List<WrappedResourceProvider> providerList = new ArrayList<WrappedResourceProvider>(
-                set);
+    private ProviderHandler[] conditionalSort(final Set<ProviderHandler> set) {
 
-        Collections.sort(providerList, new Comparator<WrappedResourceProvider>() {
+        final List<ProviderHandler> providerList = new ArrayList<ProviderHandler>(set);
 
-            @SuppressWarnings("unchecked")
-            public int compare(WrappedResourceProvider o1, WrappedResourceProvider o2) {
-                Comparable c1 = o1.getComparable();
-                Comparable c2 = o2.getComparable();
-                if ( c1 == null && c2 == null ) {
-                  return 0;
-                }
-                if ( c1 == null ) {
-                  return -1;
-                }
-                if ( c2 == null ) {
-                  return 1;
-                }
-                return c1.compareTo(c2);
-            }
-        });
+        Collections.sort(providerList);
 
-        return set.toArray(new WrappedResourceProvider[set.size()]);
+        return providerList.toArray(new ProviderHandler[providerList.size()]);
     }
 
     /**
@@ -282,11 +243,10 @@ public class ResourceProviderEntry imple
      * @param fullPath
      *            the full path
      */
-    private void populateProviderPath(
-        List<ResourceProviderEntry> providerEntryPath, String[] elements) {
+    private void populateProviderPath(final List<ResourceProviderEntry> providerEntryPath, final String[] elements) {
         ResourceProviderEntry base = this;
         if (elements != null) {
-            for (String element : elements) {
+            for (final String element : elements) {
                 if (element != null) {
                     if (base.containsKey(element)) {
                         base = base.get(element);
@@ -299,7 +259,6 @@ public class ResourceProviderEntry imple
         }
     }
 
-
     /**
      * Resolve a resource from a path into a Resource
      *
@@ -309,41 +268,36 @@ public class ResourceProviderEntry imple
      *            the Full path
      * @return null if no resource was found, a resource if one was found.
      */
-    private Resource getInternalResource(ResourceResolver resourceResolver,
-            String fullPath) {
-        long start = System.currentTimeMillis();
+    private Resource getInternalResource(final ResourceResolverContext ctx, final ResourceResolver resourceResolver, final String fullPath) {
+        final long start = System.currentTimeMillis();
         try {
 
-            if (fullPath == null || fullPath.length() == 0
-                    || fullPath.charAt(0) != '/') {
+            if (fullPath == null || fullPath.length() == 0 || fullPath.charAt(0) != '/') {
                 nmiss++;
-                LOGGER.debug("Not absolute {} :{}",fullPath,(System.currentTimeMillis() - start));
+                LOGGER.debug("Not absolute {} :{}", fullPath, (System.currentTimeMillis() - start));
                 return null; // fullpath must be absolute
             }
-            String[] elements = split(fullPath, '/');
+            final String[] elements = split(fullPath, '/');
 
-            List<ResourceProviderEntry> list = new ArrayList<ResourceProviderEntry>();
+            final List<ResourceProviderEntry> list = new ArrayList<ResourceProviderEntry>();
             populateProviderPath(list, elements);
             // the path is in reverse order end first
 
-            for(int i = list.size()-1; i >= 0; i--) {
-                ResourceProvider[] rps = list.get(i).getResourceProviders();
-                for (ResourceProvider rp : rps) {
+            for (int i = list.size() - 1; i >= 0; i--) {
+                final ProviderHandler[] rps = list.get(i).getResourceProviders();
+                for (final ProviderHandler rp : rps) {
 
-                    Resource resource = rp.getResource(resourceResolver,
-                            fullPath);
+                    final Resource resource = rp.getResource(ctx, resourceResolver, fullPath);
                     if (resource != null) {
                         nreal++;
-                        LOGGER.debug("Resolved Full {} using {} from {} ",new Object[]{
-                                fullPath, rp, Arrays.toString(rps)});
+                        LOGGER.debug("Resolved Full {} using {} from {} ", new Object[] { fullPath, rp, Arrays.toString(rps) });
                         return resource;
                     }
                 }
             }
 
             // resolve against this one
-            final Resource resource = getResourceFromProviders(
-                resourceResolver, fullPath);
+            final Resource resource = getResourceFromProviders(ctx, resourceResolver, fullPath);
             if (resource != null) {
                 return resource;
             }
@@ -352,34 +306,29 @@ public class ResourceProviderEntry imple
             // resource Provider: libs/sling/servlet/default/GET.servlet
             // list will match libs, sling, servlet, default
             // and there will be no resource provider at the end
-            if (list.size() > 0 && list.size() == elements.length ) {
-                if ( list.get(list.size()-1).getResourceProviders().length == 0 ) {
+            if (list.size() > 0 && list.size() == elements.length) {
+                if (list.get(list.size() - 1).getResourceProviders().length == 0) {
                     nsynthetic++;
                     LOGGER.debug("Resolved Synthetic {}", fullPath);
-                    return new SyntheticResource(resourceResolver,
-                            fullPath,
-                            ResourceProvider.RESOURCE_TYPE_SYNTHETIC);
+                    return new SyntheticResource(resourceResolver, fullPath, ResourceProvider.RESOURCE_TYPE_SYNTHETIC);
                 }
             }
 
-
-
             LOGGER.debug("Resource null {} ", fullPath);
             nmiss++;
             return null;
-        } catch (Exception ex) {
-            LOGGER.debug("Failed! ",ex);
+        } catch (final Exception ex) {
+            LOGGER.debug("Failed! ", ex);
             return null;
         } finally {
             ttime += System.currentTimeMillis() - start;
         }
     }
 
-    Resource getResourceFromProviders(final ResourceResolver resourceResolver,
-            final String fullPath) {
-        ResourceProvider[] rps = getResourceProviders();
-        for (ResourceProvider rp : rps) {
-            Resource resource = rp.getResource(resourceResolver, fullPath);
+    public Resource getResourceFromProviders(final ResourceResolverContext ctx, final ResourceResolver resourceResolver, final String fullPath) {
+        final ProviderHandler[] rps = getResourceProviders();
+        for (final ProviderHandler rp : rps) {
+            final Resource resource = rp.getResource(ctx, resourceResolver, fullPath);
             if (resource != null) {
                 nreal++;
                 LOGGER.debug("Resolved Base {} using {} ", fullPath, rp);
@@ -394,12 +343,12 @@ public class ResourceProviderEntry imple
      * @param sep
      * @return an array of the strings between the separator
      */
-    static String[] split(String st, char sep) {
+    public static String[] split(final String st, final char sep) {
 
         if (st == null) {
             return new String[0];
         }
-        char[] pn = st.toCharArray();
+        final char[] pn = st.toCharArray();
         if (pn.length == 0) {
             return new String[0];
         }
@@ -418,7 +367,7 @@ public class ResourceProviderEntry imple
                 n++;
             }
         }
-        String[] e = new String[n];
+        final String[] e = new String[n];
         int s = start;
         int j = 0;
         for (int i = start; i < end; i++) {
@@ -434,18 +383,17 @@ public class ResourceProviderEntry imple
     }
 
     public String getResolutionStats() {
-        long tot = nreal + nsynthetic + nmiss;
+        final long tot = nreal + nsynthetic + nmiss;
         if (tot == 0) {
             return null;
         }
-        float n = tot;
-        float t = ttime;
-        float persec = 1000 * n / t;
-        float avgtime = t / n;
-
-        String stat = "Resolved: Real(" + nreal + ") Synthetic(" + nsynthetic
-                + ") Missing(" + nmiss + ") Total(" + tot + ") at " + persec
-                + " ops/sec avg " + avgtime + " ms";
+        final float n = tot;
+        final float t = ttime;
+        final float persec = 1000 * n / t;
+        final float avgtime = t / n;
+
+        final String stat = "Resolved: Real(" + nreal + ") Synthetic(" + nsynthetic + ") Missing(" + nmiss + ") Total(" + tot + ") at "
+                        + persec + " ops/sec avg " + avgtime + " ms";
         ttime = nmiss = nsynthetic = nreal = 0L;
         return stat;
     }
@@ -458,7 +406,8 @@ public class ResourceProviderEntry imple
     @Override
     public String toString() {
         return this.path;
-        //"{path:\"" + this.path + "\", providers:"+Arrays.toString(getResourceProviders())+", map:" + storageMap.toString() + "}";
+        // "{path:\"" + this.path +
+        // "\", providers:"+Arrays.toString(getResourceProviders())+", map:" +
+        // storageMap.toString() + "}";
     }
-
 }

Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/RootResourceProviderEntry.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/RootResourceProviderEntry.java?rev=1350169&r1=1350168&r2=1350169&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/RootResourceProviderEntry.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/RootResourceProviderEntry.java Thu Jun 14 09:52:08 2012
@@ -16,124 +16,403 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.sling.jcr.resource.internal.helper;
+package org.apache.sling.resourceresolver.impl.tree;
 
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.Dictionary;
+import java.util.HashSet;
 import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
 
 import org.apache.sling.api.SlingConstants;
+import org.apache.sling.api.adapter.Adaptable;
+import org.apache.sling.api.resource.AttributableResourceProvider;
+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.ResourceProvider;
-import org.apache.sling.commons.osgi.OsgiUtil;
-import org.osgi.framework.Constants;
+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.commons.osgi.PropertiesUtil;
+import org.apache.sling.resourceresolver.impl.helper.ResourceResolverContext;
+import org.apache.sling.resourceresolver.impl.helper.SortedProviderList;
 import org.osgi.service.event.Event;
 import org.osgi.service.event.EventAdmin;
-import org.osgi.util.tracker.ServiceTracker;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * This is the root resource provider entry which keeps track
- * of the resource providers.
+ * This is the root resource provider entry which keeps track of the resource
+ * providers.
  */
 public class RootResourceProviderEntry extends ResourceProviderEntry {
 
-    /** default logger */
+    /** Default logger */
     private final Logger logger = LoggerFactory.getLogger(getClass());
 
+    /** Event admin. */
+    private EventAdmin eventAdmin;
+
+    /** Array of required factories. */
+    private ResourceProviderFactoryHandler[] requiredFactories = new ResourceProviderFactoryHandler[0];
+
+    /** All adaptable resource providers. */
+    private final SortedProviderList<Adaptable> adaptableProviders = new SortedProviderList<Adaptable>(Adaptable.class);
+
+    /** All queriable resource providers. */
+    private final SortedProviderList<QueriableResourceProvider> queriableProviders = new SortedProviderList<QueriableResourceProvider>(QueriableResourceProvider.class);
+
+    /** All attributable resource providers. */
+    private final SortedProviderList<AttributableResourceProvider> attributableProviders = new SortedProviderList<AttributableResourceProvider>(AttributableResourceProvider.class);
+
     public RootResourceProviderEntry() {
         super("/", null);
     }
 
-    public void bindResourceProvider(final ResourceProvider provider,
-                                     final Map<String, Object> props,
-                                     final ServiceTracker eventAdminTracker) {
+    /**
+     * Set or unset the event admin.
+     */
+    public void setEventAdmin(final EventAdmin ea) {
+        this.eventAdmin = ea;
+    }
+
+    /**
+     * Login into all required factories
+     * @throws LoginException If login fails.
+     */
+    public void loginToRequiredFactories(final ResourceResolverContext ctx) throws LoginException {
+        try {
+            final ResourceProviderFactoryHandler[] factories = this.requiredFactories;
+            for (final ResourceProviderFactoryHandler wrapper : factories) {
+                wrapper.login(ctx);
+            }
+        } catch (final LoginException le) {
+            // login failed, so logout if already logged in providers
+            ctx.close();
+            throw le;
+        }
+    }
 
-        final String serviceName = getServiceName(provider, props);
+    /**
+     * Invoke all resource providers and find an adaption
+     * @see Adaptable
+     */
+    public <AdapterType> AdapterType adaptTo(final ResourceResolverContext ctx, final Class<AdapterType> type) {
+        final Iterator<Adaptable> i = this.adaptableProviders.getProviders(ctx);
+        AdapterType result = null;
+        while ( result == null && i.hasNext() ) {
+            final Adaptable adap = i.next();
+            result = adap.adaptTo(type);
+        }
+        return result;
+    }
 
-        logger.debug("bindResourceProvider: Binding {}", serviceName);
+    /**
+     * Invoke all queriable resource providers.
+     * @see QueriableResourceProvider#findResources(ResourceResolver, String, String)
+     */
+    public Iterator<Resource> findResources(final ResourceResolverContext ctx,
+                    final ResourceResolver resolver, final String query, final String language) {
+        final Iterator<QueriableResourceProvider> i = this.queriableProviders.getProviders(ctx);
+        return new Iterator<Resource>() {
+
+            private Resource nextObject = this.seek();
+
+            private Iterator<Resource> nextResourceIter;
+
+            private Resource seek() {
+                Resource result = null;
+                if ( nextResourceIter == null || !nextResourceIter.hasNext() ) {
+                    nextResourceIter = null;
+                    while ( i.hasNext() && nextResourceIter == null ) {
+                        final QueriableResourceProvider adap = i.next();
+                        nextResourceIter = adap.findResources(resolver, query, language);
+                    }
+                }
+                if ( nextResourceIter != null ) {
+                    while ( nextResourceIter.hasNext() && result == null ) {
+                        result = nextResourceIter.next();
+                    }
+                    if ( result == null ) {
+                        result = seek();
+                    }
+                }
+                return result;
+            }
 
-        String[] roots = OsgiUtil.toStringArray(props.get(ResourceProvider.ROOTS));
-        if (roots != null && roots.length > 0) {
-            final EventAdmin localEA = (EventAdmin) ( eventAdminTracker != null ? eventAdminTracker.getService() : null);
+            /**
+             * @see java.util.Iterator#hasNext()
+             */
+            public boolean hasNext() {
+                return this.nextObject != null;
+            }
 
-            for (String root : roots) {
-                // cut off trailing slash
-                if (root.endsWith("/") && root.length() > 1) {
-                    root = root.substring(0, root.length() - 1);
+            /**
+             * @see java.util.Iterator#next()
+             */
+            public Resource next() {
+                if ( this.nextObject == null ) {
+                    throw new NoSuchElementException();
                 }
+                final Resource result = this.nextObject;
+                this.nextObject = this.seek();
+                return result;
+            }
 
-                // synchronized insertion of new resource providers into
-                // the tree to not inadvertently loose an entry
-                synchronized (this) {
+            /**
+             * @see java.util.Iterator#remove()
+             */
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
 
-                    this.addResourceProvider(root,
-                        provider, OsgiUtil.getComparableForServiceRanking(props));
+    /**
+     * Invoke all queriable resource providers.
+     * @see QueriableResourceProvider#queryResources(String, String)
+     */
+    public Iterator<Map<String, Object>> queryResources(final ResourceResolverContext ctx, final String query, final String language) {
+        final Iterator<QueriableResourceProvider> i = this.queriableProviders.getProviders(ctx);
+        return new Iterator<Map<String, Object>>() {
+
+            private Map<String, Object> nextObject = this.seek();
+
+            private Iterator<Map<String, Object>> nextResourceIter;
+
+            private Map<String, Object> seek() {
+                Map<String, Object> result = null;
+                if ( nextResourceIter == null || !nextResourceIter.hasNext() ) {
+                    nextResourceIter = null;
+                    while ( i.hasNext() && nextResourceIter == null ) {
+                        final QueriableResourceProvider adap = i.next();
+                        nextResourceIter = adap.queryResources(query, language);
+                    }
                 }
-                logger.debug("bindResourceProvider: {}={} ({})",
-                    new Object[] { root, provider, serviceName });
-                if ( localEA != null ) {
-                    final Dictionary<String, Object> eventProps = new Hashtable<String, Object>();
-                    eventProps.put(SlingConstants.PROPERTY_PATH, root);
-                    localEA.postEvent(new Event(SlingConstants.TOPIC_RESOURCE_PROVIDER_ADDED,
-                            eventProps));
+                if ( nextResourceIter != null ) {
+                    while ( nextResourceIter.hasNext() && result == null ) {
+                        result = nextResourceIter.next();
+                    }
+                    if ( result == null ) {
+                        result = seek();
+                    }
                 }
+                return result;
+            }
+
+            /**
+             * @see java.util.Iterator#hasNext()
+             */
+            public boolean hasNext() {
+                return this.nextObject != null;
             }
+
+            /**
+             * @see java.util.Iterator#next()
+             */
+            public Map<String, Object> next() {
+                if ( this.nextObject == null ) {
+                    throw new NoSuchElementException();
+                }
+                final Map<String, Object> result = this.nextObject;
+                this.nextObject = this.seek();
+                return result;
+            }
+
+            /**
+             * @see java.util.Iterator#remove()
+             */
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    private static final String FORBIDDEN_ATTRIBUTE = ResourceResolverFactory.PASSWORD;
+
+    /**
+     * Invoke all attributes providers and combine the result
+     * @see AttributableResourceProvider#getAttributeNames()
+     */
+    public Iterator<String> getAttributeNames(final ResourceResolverContext ctx) {
+        final Set<String> names = new HashSet<String>();
+        if ( ctx.getAuthenticationInfo() != null ) {
+            names.addAll(ctx.getAuthenticationInfo().keySet());
         }
+        final Iterator<AttributableResourceProvider> i = this.attributableProviders.getProviders(ctx);
+        while ( i.hasNext() ) {
+            final AttributableResourceProvider adap = i.next();
+            final Collection<String> newNames = adap.getAttributeNames();
+            if ( newNames != null ) {
+                names.addAll(newNames);
+            }
+        }
+        names.remove(FORBIDDEN_ATTRIBUTE);
 
-        logger.debug("bindResourceProvider: Bound {}", serviceName);
+        return names.iterator();
     }
 
-    public void unbindResourceProvider(final ResourceProvider provider,
-                                       final Map<String, Object> props,
-                                       final ServiceTracker eventAdminTracker) {
+    /**
+     * Return the result from the first matching attributes provider
+     * @see AttributableResourceProvider#getAttribute(String)
+     */
+    public Object getAttribute(final ResourceResolverContext ctx, final String name) {
+        Object result = null;
+        if (!FORBIDDEN_ATTRIBUTE.equals(name) )  {
+            if (ctx.getAuthenticationInfo() != null) {
+                result = ctx.getAuthenticationInfo().get(name);
+            }
+            if ( result == null ) {
+                final Iterator<AttributableResourceProvider> i = this.attributableProviders.getProviders(ctx);
+                while ( result == null && i.hasNext() ) {
+                    final AttributableResourceProvider adap = i.next();
+                    result = adap.getAttribute(name);
+                }
+            }
+        }
+        return result;
+    }
 
-        final String serviceName = getServiceName(provider, props);
+    /**
+     * Bind a resource provider.
+     */
+    public void bindResourceProvider(final ResourceProvider provider, final Map<String, Object> props) {
+        final ResourceProviderHandler handler = new ResourceProviderHandler(provider, props);
+
+        this.bindHandler(handler);
+        this.adaptableProviders.add(handler);
+        this.queriableProviders.add(handler);
+        this.attributableProviders.add(handler);
+    }
 
-        logger.debug("unbindResourceProvider: Unbinding {}", serviceName);
+    /**
+     * Unbind a resource provider.
+     */
+    public void unbindResourceProvider(final ResourceProvider provider, final Map<String, Object> props) {
+        final ResourceProviderHandler handler = new ResourceProviderHandler(provider, props);
+
+        this.unbindHandler(handler);
+        this.adaptableProviders.remove(handler);
+        this.queriableProviders.remove(handler);
+        this.attributableProviders.remove(handler);
+    }
+
+    /**
+     * Bind a resource provider factory.
+     */
+    public void bindResourceProviderFactory(final ResourceProviderFactory factory, final Map<String, Object> props) {
+        final ResourceProviderFactoryHandler handler = new ResourceProviderFactoryHandler(factory, props);
+
+        this.bindHandler(handler);
+        this.adaptableProviders.add(handler);
+        this.queriableProviders.add(handler);
+        this.attributableProviders.add(handler);
+
+        final boolean required = PropertiesUtil.toBoolean(props.get(ResourceProviderFactory.PROPERTY_REQUIRED), false);
+        if (required) {
+            synchronized (this) {
+                final List<ResourceProviderFactoryHandler> factories = new LinkedList<ResourceProviderFactoryHandler>();
+                factories.addAll(Arrays.asList(this.requiredFactories));
+                factories.add(handler);
+                this.requiredFactories = factories.toArray(new ResourceProviderFactoryHandler[factories.size()]);
+            }
+        }
+    }
+
+    /**
+     * Unbind a resource provider factory
+     */
+    public void unbindResourceProviderFactory(final ResourceProviderFactory factory, final Map<String, Object> props) {
+        final ResourceProviderFactoryHandler handler = new ResourceProviderFactoryHandler(factory, props);
+
+        this.unbindHandler(handler);
+        this.adaptableProviders.remove(handler);
+        this.queriableProviders.remove(handler);
+        this.attributableProviders.remove(handler);
+
+        final boolean required = PropertiesUtil.toBoolean(props.get(ResourceProviderFactory.PROPERTY_REQUIRED), false);
+        if (required) {
+            synchronized (this) {
+                final List<ResourceProviderFactoryHandler> factories = new LinkedList<ResourceProviderFactoryHandler>();
+                factories.addAll(Arrays.asList(this.requiredFactories));
+                factories.remove(handler);
+                this.requiredFactories = factories.toArray(new ResourceProviderFactoryHandler[factories.size()]);
+            }
+        }
+    }
 
-        String[] roots = OsgiUtil.toStringArray(props.get(ResourceProvider.ROOTS));
-        if (roots != null && roots.length > 0) {
+    /**
+     * Bind a resource provider wrapper
+     */
+    private void bindHandler(final ProviderHandler provider) {
+        // this is just used for debug logging
+        final String debugServiceName = getDebugServiceName(provider);
+
+        logger.debug("bindResourceProvider: Binding {}", debugServiceName);
+
+        final String[] roots = provider.getRoots();
+        boolean foundRoot = false;
+        if (roots != null) {
+            final EventAdmin localEA = this.eventAdmin;
+            for (final String root : roots) {
+                foundRoot = true;
 
-            final EventAdmin localEA = (EventAdmin) ( eventAdminTracker != null ? eventAdminTracker.getService() : null);
+                this.addResourceProvider(root, provider);
 
-            for (String root : roots) {
-                // cut off trailing slash
-                if (root.endsWith("/") && root.length() > 1) {
-                    root = root.substring(0, root.length() - 1);
+                logger.debug("bindResourceProvider: {}={} ({})", new Object[] { root, provider, debugServiceName });
+                if (localEA != null) {
+                    final Dictionary<String, Object> eventProps = new Hashtable<String, Object>();
+                    eventProps.put(SlingConstants.PROPERTY_PATH, root);
+                    localEA.postEvent(new Event(SlingConstants.TOPIC_RESOURCE_PROVIDER_ADDED, eventProps));
                 }
+            }
+        }
+        if ( !foundRoot ) {
+            logger.info("Ignoring ResourceProvider(Factory) {} : no configured roots.", provider.getName());
+        }
+        logger.debug("bindResourceProvider: Bound {}", debugServiceName);
+    }
 
-                // synchronized insertion of new resource providers into
-                // the tree to not inadvertently loose an entry
-                synchronized (this) {
-                    // TODO: Do not remove this path, if another resource
-                    // owns it. This may be the case if adding the provider
-                    // yielded an ResourceProviderEntryException
-                    this.removeResourceProvider(root, provider, OsgiUtil.getComparableForServiceRanking(props));
-                }
-                logger.debug("unbindResourceProvider: root={} ({})", root,
-                    serviceName);
-                if ( localEA != null ) {
+    /**
+     * Unbind a resource provider wrapper
+     */
+    private void unbindHandler(final ProviderHandler provider) {
+        // this is just used for debug logging
+        final String debugServiceName = getDebugServiceName(provider);
+
+        logger.debug("unbindResourceProvider: Unbinding {}", debugServiceName);
+
+        final String[] roots = provider.getRoots();
+        if (roots != null) {
+
+            final EventAdmin localEA = this.eventAdmin;
+
+            for (final String root : roots) {
+
+                this.removeResourceProvider(root, provider);
+
+                logger.debug("unbindResourceProvider: root={} ({})", root, debugServiceName);
+                if (localEA != null) {
                     final Dictionary<String, Object> eventProps = new Hashtable<String, Object>();
                     eventProps.put(SlingConstants.PROPERTY_PATH, root);
-                    localEA.postEvent(new Event(SlingConstants.TOPIC_RESOURCE_PROVIDER_REMOVED,
-                            eventProps));
+                    localEA.postEvent(new Event(SlingConstants.TOPIC_RESOURCE_PROVIDER_REMOVED, eventProps));
                 }
             }
         }
 
-        logger.debug("unbindResourceProvider: Unbound {}", serviceName);
+        logger.debug("unbindResourceProvider: Unbound {}", debugServiceName);
     }
 
-    private String getServiceName(final ResourceProvider provider, final Map<String, Object> props) {
+    private String getDebugServiceName(final ProviderHandler provider) {
         if (logger.isDebugEnabled()) {
-            StringBuilder snBuilder = new StringBuilder(64);
-            snBuilder.append('{');
-            snBuilder.append(provider.toString());
-            snBuilder.append('/');
-            snBuilder.append(props.get(Constants.SERVICE_ID));
-            snBuilder.append('}');
-            return snBuilder.toString();
+            return provider.getName();
         }
 
         return null;

Added: 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=1350169&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java (added)
+++ sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java Thu Jun 14 09:52:08 2012
@@ -0,0 +1,547 @@
+/*
+ * 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.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.BufferedReader;
+import java.security.Principal;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.jcr.Session;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.apache.sling.api.resource.NonExistingResource;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.resourceresolver.impl.helper.ResourceResolverContext;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ResourceResolverImplTest {
+
+    private ResourceResolver resResolver;
+
+    private ResourceResolverFactoryImpl resFac;
+
+    @Before public void setup() {
+        resFac = new ResourceResolverFactoryImpl();
+        resResolver = new ResourceResolverImpl(resFac, new ResourceResolverContext(false, null));
+    }
+
+    @Test public void testClose() throws Exception {
+        final ResourceResolver rr = new ResourceResolverImpl(resFac, new ResourceResolverContext(false, null));
+        assertTrue(rr.isLive());
+        rr.close();
+        assertFalse(rr.isLive());
+        // close is always allowed to be called
+        rr.close();
+        assertFalse(rr.isLive());
+        // now check all public method - they should all throw!
+        try {
+            rr.adaptTo(Session.class);
+            fail();
+        } catch (final IllegalStateException ise) {
+            // expected
+        }
+        try {
+            rr.clone(null);
+            fail();
+        } catch (final IllegalStateException ise) {
+            // expected
+        }
+        try {
+            rr.findResources("a", "b");
+            fail();
+        } catch (final IllegalStateException ise) {
+            // expected
+        }
+        try {
+            rr.getAttribute("a");
+            fail();
+        } catch (final IllegalStateException ise) {
+            // expected
+        }
+        try {
+            rr.getAttributeNames();
+            fail();
+        } catch (final IllegalStateException ise) {
+            // expected
+        }
+        try {
+            rr.getResource(null);
+            fail();
+        } catch (final IllegalStateException ise) {
+            // expected
+        }
+        try {
+            rr.getResource(null, "/a");
+            fail();
+        } catch (final IllegalStateException ise) {
+            // expected
+        }
+        try {
+            rr.getSearchPath();
+            fail();
+        } catch (final IllegalStateException ise) {
+            // expected
+        }
+        try {
+            rr.getUserID();
+            fail();
+        } catch (final IllegalStateException ise) {
+            // expected
+        }
+        try {
+            rr.listChildren(null);
+            fail();
+        } catch (final IllegalStateException ise) {
+            // expected
+        }
+        try {
+            rr.map("/somepath");
+            fail();
+        } catch (final IllegalStateException ise) {
+            // expected
+        }
+        try {
+            rr.map(null, "/somepath");
+            fail();
+        } catch (final IllegalStateException ise) {
+            // expected
+        }
+        try {
+            rr.queryResources("a", "b");
+            fail();
+        } catch (final IllegalStateException ise) {
+            // expected
+        }
+        try {
+            rr.resolve((HttpServletRequest)null);
+            fail();
+        } catch (final IllegalStateException ise) {
+            // expected
+        }
+        try {
+            rr.resolve("/path");
+            fail();
+        } catch (final IllegalStateException ise) {
+            // expected
+        }
+        try {
+            rr.resolve(null, "/path");
+            fail();
+        } catch (final IllegalStateException ise) {
+            // expected
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    @Test public void testBasicAPIAssumptions() throws Exception {
+
+        // null resource is accessing /, which exists of course
+        final Resource res00 = resResolver.resolve((String) null);
+        assertNotNull(res00);
+        assertTrue("Resource must be NonExistingResource",
+                        res00 instanceof NonExistingResource);
+        assertEquals("Null path is expected to return root", "/",
+            res00.getPath());
+
+        // relative paths are treated as if absolute
+        final String path01 = "relPath/relPath";
+        final Resource res01 = resResolver.resolve(path01);
+        assertNotNull(res01);
+        assertEquals("Expecting absolute path for relative path", "/" + path01,
+            res01.getPath());
+        assertTrue("Resource must be NonExistingResource",
+            res01 instanceof NonExistingResource);
+
+        final String no_resource_path = "/no_resource/at/this/location";
+        final Resource res02 = resResolver.resolve(no_resource_path);
+        assertNotNull(res02);
+        assertEquals("Expecting absolute path for relative path",
+            no_resource_path, res02.getPath());
+        assertTrue("Resource must be NonExistingResource",
+            res01 instanceof NonExistingResource);
+
+        try {
+            resResolver.resolve((HttpServletRequest) null);
+            fail("Expected NullPointerException trying to resolve null request");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+
+        final Resource res0 = resResolver.resolve(null, no_resource_path);
+        assertNotNull("Expecting resource if resolution fails", res0);
+        assertTrue("Resource must be NonExistingResource",
+            res0 instanceof NonExistingResource);
+        assertEquals("Path must be the original path", no_resource_path,
+            res0.getPath());
+
+        final HttpServletRequest req1 = new ResourceResolverTestRequest(
+            no_resource_path);
+        final Resource res1 = resResolver.resolve(req1);
+        assertNotNull("Expecting resource if resolution fails", res1);
+        assertTrue("Resource must be NonExistingResource",
+            res1 instanceof NonExistingResource);
+        assertEquals("Path must be the original path", no_resource_path,
+            res1.getPath());
+
+        final HttpServletRequest req2 = new ResourceResolverTestRequest(null);
+        final Resource res2 = resResolver.resolve(req2);
+        assertNotNull("Expecting resource if resolution fails", res2);
+        assertTrue("Resource must be NonExistingResource",
+            res2 instanceof NonExistingResource);
+        assertEquals("Path must be the the root path", "/", res2.getPath());
+    }
+
+    @Test public void test_clone_based_on_anonymous() throws Exception {
+        final ResourceResolver anon0 = resFac.getResourceResolver((Map<String, Object>) null);
+        // no session
+        final Session anon0Session = anon0.adaptTo(Session.class);
+        assertNull("Session should not be available", anon0Session);
+        // no user information, so user id is null
+        assertEquals(null, anon0.getUserID());
+
+        // same user and workspace
+        final ResourceResolver anon1 = anon0.clone(null);
+        final Session anon1Session = anon1.adaptTo(Session.class);
+        assertEquals(anon0.getUserID(), anon1.getUserID());
+        assertNull("Session should not be available", anon1Session);
+        anon1.close();
+
+        // same workspace but admin user
+        final Map<String, Object> admin0Cred = new HashMap<String, Object>();
+        admin0Cred.put(ResourceResolverFactory.USER, "admin");
+        admin0Cred.put(ResourceResolverFactory.PASSWORD, "admin".toCharArray());
+        final ResourceResolver admin0 = anon0.clone(admin0Cred);
+        assertEquals("admin", admin0.getUserID());
+        admin0.close();
+
+        anon0.close();
+    }
+
+    @Test public void test_clone_based_on_admin() throws Exception {
+        final ResourceResolver admin0 = resFac.getAdministrativeResourceResolver((Map<String, Object>) null);
+        // no user information, so user id is null
+        assertEquals(null, admin0.getUserID());
+
+        // same user and workspace
+        final ResourceResolver admin1 = admin0.clone(null);
+        assertEquals(admin0.getUserID(), admin1.getUserID());
+        admin1.close();
+
+        // same workspace but anonymous user
+        final Map<String, Object> anon0Cred = new HashMap<String, Object>();
+        anon0Cred.put(ResourceResolverFactory.USER, "anonymous");
+        final ResourceResolver anon0 = admin0.clone(anon0Cred);
+        assertEquals("anonymous", anon0.getUserID());
+        anon0.close();
+
+        admin0.close();
+    }
+
+    @Test public void test_attributes_from_authInfo() throws Exception {
+        final Map<String, Object> authInfo = new HashMap<String, Object>();
+        authInfo.put(ResourceResolverFactory.USER, "admin");
+        authInfo.put(ResourceResolverFactory.PASSWORD, "admin".toCharArray());
+        authInfo.put("testAttributeString", "AStringValue");
+        authInfo.put("testAttributeNumber", 999);
+        final ResourceResolver rr = resFac.getResourceResolver(authInfo);
+
+        assertEquals("AStringValue", rr.getAttribute("testAttributeString"));
+        assertEquals(999, rr.getAttribute("testAttributeNumber"));
+        assertEquals("admin", rr.getAttribute(ResourceResolverFactory.USER));
+        assertNull(rr.getAttribute(ResourceResolverFactory.PASSWORD));
+
+        final HashSet<String> validNames = new HashSet<String>();
+        validNames.add(ResourceResolverFactory.USER);
+        validNames.add("testAttributeString");
+        validNames.add("testAttributeNumber");
+        final Iterator<String> names = rr.getAttributeNames();
+        assertTrue(validNames.remove(names.next()));
+        assertTrue(validNames.remove(names.next()));
+        assertTrue(validNames.remove(names.next()));
+        assertFalse("Expect no more names", names.hasNext());
+        assertTrue("Expect validNames set to be empty now",
+            validNames.isEmpty());
+
+        rr.close();
+    }
+
+    private static final class ResourceResolverTestRequest implements
+    HttpServletRequest {
+
+        private final String pathInfo;
+
+        private final String method;
+
+        private final String scheme;
+
+        private final String host;
+
+        private final int port;
+
+        private final Map<String, Object> attrs = new HashMap<String, Object>();
+
+        private String contextPath;
+
+        ResourceResolverTestRequest(String pathInfo) {
+            this(null, null, -1, pathInfo, null);
+        }
+
+        ResourceResolverTestRequest(String scheme, String host, int port,
+                String pathInfo, String httpMethod) {
+            this.scheme = (scheme == null) ? "http" : scheme;
+            this.host = (host == null) ? "localhost" : host;
+            this.port = port;
+            this.pathInfo = pathInfo;
+            this.method = httpMethod;
+        }
+
+        public String getPathInfo() {
+            return pathInfo;
+        }
+
+        public Object getAttribute(String name) {
+            return attrs.get(name);
+        }
+
+        public Enumeration<?> getAttributeNames() {
+            return null;
+        }
+
+        public String getCharacterEncoding() {
+            return null;
+        }
+
+        public int getContentLength() {
+            return 0;
+        }
+
+        public String getContentType() {
+            return null;
+        }
+
+        public ServletInputStream getInputStream() {
+            return null;
+        }
+
+        public String getLocalAddr() {
+            return null;
+        }
+
+        public String getLocalName() {
+            return null;
+        }
+
+        public int getLocalPort() {
+            return 0;
+        }
+
+        public Locale getLocale() {
+            return null;
+        }
+
+        public Enumeration<?> getLocales() {
+            return null;
+        }
+
+        public String getParameter(String name) {
+            return null;
+        }
+
+        public Map<?, ?> getParameterMap() {
+            return null;
+        }
+
+        public Enumeration<?> getParameterNames() {
+            return null;
+        }
+
+        public String[] getParameterValues(String name) {
+            return null;
+        }
+
+        public String getProtocol() {
+            return null;
+        }
+
+        public BufferedReader getReader() {
+            return null;
+        }
+
+        public String getRealPath(String path) {
+            return null;
+        }
+
+        public String getRemoteAddr() {
+            return null;
+        }
+
+        public String getRemoteHost() {
+            return null;
+        }
+
+        public int getRemotePort() {
+            return 0;
+        }
+
+        public RequestDispatcher getRequestDispatcher(String path) {
+            return null;
+        }
+
+        public String getScheme() {
+            return scheme;
+        }
+
+        public String getServerName() {
+            return host;
+        }
+
+        public int getServerPort() {
+            return port;
+        }
+
+        public boolean isSecure() {
+            return false;
+        }
+
+        public String getContextPath() {
+            return contextPath;
+        }
+
+        public void removeAttribute(String name) {
+        }
+
+        public void setAttribute(String name, Object o) {
+            attrs.put(name, o);
+        }
+
+        public void setCharacterEncoding(String env) {
+        }
+
+        public String getAuthType() {
+            return null;
+        }
+
+        public Cookie[] getCookies() {
+            return null;
+        }
+
+        public long getDateHeader(String name) {
+            return 0;
+        }
+
+        public String getHeader(String name) {
+            return null;
+        }
+
+        public Enumeration<?> getHeaderNames() {
+            return null;
+        }
+
+        public Enumeration<?> getHeaders(String name) {
+            return null;
+        }
+
+        public int getIntHeader(String name) {
+            return 0;
+        }
+
+        public String getMethod() {
+            return method;
+        }
+
+        public String getPathTranslated() {
+            return null;
+        }
+
+        public String getQueryString() {
+            return null;
+        }
+
+        public String getRemoteUser() {
+            return null;
+        }
+
+        public String getRequestURI() {
+            return null;
+        }
+
+        public StringBuffer getRequestURL() {
+            return null;
+        }
+
+        public String getRequestedSessionId() {
+            return null;
+        }
+
+        public String getServletPath() {
+            return null;
+        }
+
+        public HttpSession getSession() {
+            return null;
+        }
+
+        public HttpSession getSession(boolean create) {
+            return null;
+        }
+
+        public Principal getUserPrincipal() {
+            return null;
+        }
+
+        public boolean isRequestedSessionIdFromCookie() {
+            return false;
+        }
+
+        public boolean isRequestedSessionIdFromURL() {
+            return false;
+        }
+
+        public boolean isRequestedSessionIdFromUrl() {
+            return false;
+        }
+
+        public boolean isRequestedSessionIdValid() {
+            return false;
+        }
+
+        public boolean isUserInRole(String role) {
+            return false;
+        }
+    }
+}

Propchange: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/RedirectResourceTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/RedirectResourceTest.java?rev=1350169&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/RedirectResourceTest.java (added)
+++ sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/RedirectResourceTest.java Thu Jun 14 09:52:08 2012
@@ -0,0 +1,59 @@
+/*
+ * 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.helper;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.Map;
+
+import org.apache.sling.api.resource.PersistableValueMap;
+import org.apache.sling.api.resource.ValueMap;
+import org.junit.Test;
+
+public class RedirectResourceTest {
+
+    @Test public void testRedirectResource() {
+
+        final String path = "/redir/path";
+        final String target = "/redir/target";
+        final int status = 999;
+        final RedirectResource res = new RedirectResource(null, path, target,
+            status);
+
+        assertEquals(path, res.getPath());
+        assertEquals(RedirectResource.RT_SLING_REDIRECT, res.getResourceType());
+
+        final Map<?, ?> map = res.adaptTo(Map.class);
+        assertNotNull("Expected Map adapter", map);
+        assertEquals(target, map.get(RedirectResource.PROP_SLING_TARGET));
+        assertEquals(status, ((Integer) map.get(RedirectResource.PROP_SLING_STATUS)).intValue());
+
+        final ValueMap valueMap = res.adaptTo(ValueMap.class);
+        assertNotNull("Expected ValueMap adapter", valueMap);
+        assertEquals(target, valueMap.get(RedirectResource.PROP_SLING_TARGET));
+        assertEquals(status, ((Integer) valueMap.get(RedirectResource.PROP_SLING_STATUS)).intValue());
+        assertEquals(status, valueMap.get(RedirectResource.PROP_SLING_STATUS, Integer.class).intValue());
+
+        final PersistableValueMap persistableValueMap = res.adaptTo(PersistableValueMap.class);
+        assertNull("Unexpected PersistableValueMap adapter",
+            persistableValueMap);
+    }
+}

Propchange: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/RedirectResourceTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/RedirectResourceTest.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/ResourcePathIteratorTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/ResourcePathIteratorTest.java?rev=1350169&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/ResourcePathIteratorTest.java (added)
+++ sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/ResourcePathIteratorTest.java Thu Jun 14 09:52:08 2012
@@ -0,0 +1,155 @@
+/*
+ * 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.helper;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.junit.Test;
+
+public class ResourcePathIteratorTest {
+
+    @Test public void testNull() {
+        ResourcePathIterator rpi = new ResourcePathIterator(null);
+        assertFinished(rpi);
+    }
+
+    @Test public void testEmpty() {
+        ResourcePathIterator rpi = new ResourcePathIterator("");
+        assertFinished(rpi);
+    }
+
+    @Test public void testRoot() {
+        ResourcePathIterator rpi = new ResourcePathIterator("/");
+        assertNext("/", rpi);
+        assertFinished(rpi);
+    }
+
+    @Test public void testSlashed() {
+        ResourcePathIterator rpi = new ResourcePathIterator("/root/child");
+        assertNext("/root/child", rpi);
+        assertFinished(rpi);
+    }
+
+    @Test public void testSlashedTrailingSlash1() {
+        ResourcePathIterator rpi = new ResourcePathIterator("/root/child/");
+        assertNext("/root/child", rpi);
+        assertFinished(rpi);
+    }
+
+    @Test public void testSlashedTrailingSlash2() {
+        ResourcePathIterator rpi = new ResourcePathIterator("/root/child//");
+        assertNext("/root/child", rpi);
+        assertFinished(rpi);
+    }
+
+    @Test public void testDotted() {
+        ResourcePathIterator rpi = new ResourcePathIterator("/root.child");
+        assertNext("/root.child", rpi);
+        assertNext("/root", rpi);
+        assertFinished(rpi);
+    }
+
+    @Test public void testMixed() {
+        ResourcePathIterator rpi = new ResourcePathIterator(
+            "/root/child.print.a4.html/with/suffix");
+        assertNext("/root/child.print.a4.html/with/suffix", rpi);
+        assertNext("/root/child.print.a4", rpi);
+        assertNext("/root/child.print", rpi);
+        assertNext("/root/child", rpi);
+        assertFinished(rpi);
+    }
+
+    @Test public void testNoSeparators() {
+        final Iterator<String> rpi = new ResourcePathIterator(
+            "MickeyMouseWasHere");
+        assertNext("MickeyMouseWasHere", rpi);
+        assertFinished(rpi);
+    }
+
+    @Test public void testGetA() {
+        final Iterator<String> rpi = new ResourcePathIterator(
+            "/some/stuff/more.a4.html");
+        assertNext("/some/stuff/more.a4.html", rpi);
+        assertNext("/some/stuff/more.a4", rpi);
+        assertNext("/some/stuff/more", rpi);
+        assertFinished(rpi);
+    }
+
+    @Test public void testGetB() {
+        final Iterator<String> rpi = new ResourcePathIterator(
+            "/some/stuff/more.html");
+        assertNext("/some/stuff/more.html", rpi);
+        assertNext("/some/stuff/more", rpi);
+        assertFinished(rpi);
+    }
+
+    @Test public void testHeadB() {
+        final Iterator<String> rpi = new ResourcePathIterator(
+            "/some/stuff/more.html");
+        assertNext("/some/stuff/more.html", rpi);
+        assertNext("/some/stuff/more", rpi);
+        assertFinished(rpi);
+    }
+
+    @Test public void testGetC() {
+        final Iterator<String> it = new ResourcePathIterator("/some/stuff/more");
+        assertNext("/some/stuff/more", it);
+        assertFinished(it);
+    }
+
+    @Test public void testGetD() {
+        final Iterator<String> it = new ResourcePathIterator(
+            "/some/stuff.print/more.html");
+        assertNext("/some/stuff.print/more.html", it);
+        assertNext("/some/stuff.print/more", it);
+        assertNext("/some/stuff", it);
+        assertFinished(it);
+    }
+
+    @Test public void testRelativePathGet() {
+        final Iterator<String> it = new ResourcePathIterator("some/stuff.print");
+        assertNext("some/stuff.print", it);
+        assertNext("some/stuff", it);
+        assertFinished(it);
+    }
+
+    private void assertNext(String expected, Iterator<String> iterator) {
+        assertTrue("Iterator must have next", iterator.hasNext());
+        assertEquals("Incorrect next value", expected, iterator.next());
+    }
+
+    private void assertFinished(Iterator<String> iterator) {
+
+        assertFalse("Iterator must not have next", iterator.hasNext());
+
+        try {
+            iterator.next();
+            fail("Iterator should throw NoSuchElementException");
+        } catch (NoSuchElementException nsee) {
+            // expected
+        }
+
+    }
+}
\ No newline at end of file

Propchange: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/ResourcePathIteratorTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/ResourcePathIteratorTest.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/SortedProviderListTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/SortedProviderListTest.java?rev=1350169&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/SortedProviderListTest.java (added)
+++ sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/SortedProviderListTest.java Thu Jun 14 09:52:08 2012
@@ -0,0 +1,266 @@
+/*
+ * 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.helper;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.sling.api.adapter.Adaptable;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.Resource;
+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.resourceresolver.impl.tree.ResourceProviderFactoryHandler;
+import org.apache.sling.resourceresolver.impl.tree.ResourceProviderHandler;
+import org.junit.Test;
+import org.osgi.framework.Constants;
+
+public class SortedProviderListTest {
+
+    @Test public void testAddRemoveResourceProvider() {
+        final ResourceProviderImpl rp1 = new ResourceProviderImpl(null, 1L);
+        final AdaptableResourceProviderImpl rp2 = new AdaptableResourceProviderImpl(null, 2L);
+        final AdaptableResourceProviderImpl rp3 = new AdaptableResourceProviderImpl(new String[] {"/hello"}, 3L);
+        final ResourceProviderImpl rp4 = new ResourceProviderImpl(new String[] {"/you"}, 4L);
+
+        final SortedProviderList<Adaptable> spl = new SortedProviderList<Adaptable>(Adaptable.class);
+        check(spl, null);
+        spl.add(new ResourceProviderHandler(rp1, rp1.getProperties()));
+        check(spl, null);
+        spl.add(new ResourceProviderHandler(rp2, rp2.getProperties()));
+        check(spl, null, rp2);
+        spl.add(new ResourceProviderHandler(rp3, rp3.getProperties()));
+        check(spl, null, rp2, rp3);
+        spl.add(new ResourceProviderHandler(rp4, rp4.getProperties()));
+        check(spl, null, rp2, rp3);
+
+        spl.remove(new ResourceProviderHandler(rp1, rp1.getProperties()));
+        check(spl, null, rp2, rp3);
+        spl.remove(new ResourceProviderHandler(rp1, rp1.getProperties()));
+        check(spl, null, rp2, rp3);
+        spl.remove(new ResourceProviderHandler(rp4, rp4.getProperties()));
+        check(spl, null, rp2, rp3);
+        spl.remove(new ResourceProviderHandler(rp2, rp2.getProperties()));
+        check(spl, null, rp3);
+        spl.remove(new ResourceProviderHandler(rp3, rp3.getProperties()));
+        check(spl, null);
+    }
+
+    @Test public void testSortingRP() {
+        final AdaptableResourceProviderImpl rp1 = new AdaptableResourceProviderImpl(new String[] {"/d", "/a", "x"}, 1L);
+        final AdaptableResourceProviderImpl rp2 = new AdaptableResourceProviderImpl(null, 2L);
+        final AdaptableResourceProviderImpl rp3 = new AdaptableResourceProviderImpl(new String[] {"/b"}, 3L);
+        final AdaptableResourceProviderImpl rp4 = new AdaptableResourceProviderImpl(new String[] {"/a/a"}, 4L);
+        final AdaptableResourceProviderImpl rp5 = new AdaptableResourceProviderImpl(new String[] {"/all/or/nothing"}, 5L);
+
+        final SortedProviderList<Adaptable> spl = new SortedProviderList<Adaptable>(Adaptable.class);
+        check(spl, null);
+        spl.add(new ResourceProviderHandler(rp1, rp1.getProperties()));
+        check(spl, null, rp1);
+        spl.add(new ResourceProviderHandler(rp2, rp2.getProperties()));
+        check(spl, null, rp2, rp1);
+        spl.add(new ResourceProviderHandler(rp3, rp3.getProperties()));
+        check(spl, null, rp2, rp1, rp3);
+        spl.add(new ResourceProviderHandler(rp4, rp4.getProperties()));
+        check(spl, null, rp2, rp1, rp4, rp3);
+        spl.add(new ResourceProviderHandler(rp5, rp5.getProperties()));
+        check(spl, null, rp2, rp1, rp4, rp5, rp3);
+    }
+
+    @Test public void testAddRemoveResourceProviderFactory() {
+        final ResourceProviderImpl rp1 = new ResourceProviderImpl(null, 1L);
+        final AdaptableResourceProviderImpl rp2 = new AdaptableResourceProviderImpl(null, 2L);
+        final AdaptableResourceProviderImpl rp3 = new AdaptableResourceProviderImpl(new String[] {"/hello"}, 3L);
+        final ResourceProviderImpl rp4 = new ResourceProviderImpl(new String[] {"/you"}, 4L);
+
+        final ResourceResolverContext ctx = new ResourceResolverContext(false, null);
+
+        final SortedProviderList<Adaptable> spl = new SortedProviderList<Adaptable>(Adaptable.class);
+        check(spl, ctx);
+        spl.add(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp1), rp1.getProperties()));
+        check(spl, ctx);
+        spl.add(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp2), rp2.getProperties()));
+        check(spl, ctx, rp2);
+        spl.add(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp3), rp3.getProperties()));
+        check(spl, ctx, rp2, rp3);
+        spl.add(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp4), rp4.getProperties()));
+        check(spl, ctx, rp2, rp3);
+
+        spl.remove(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp1), rp1.getProperties()));
+        check(spl, ctx, rp2, rp3);
+        spl.remove(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp1), rp1.getProperties()));
+        check(spl, ctx, rp2, rp3);
+        spl.remove(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp4), rp4.getProperties()));
+        check(spl, ctx, rp2, rp3);
+        spl.remove(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp2), rp2.getProperties()));
+        check(spl, ctx, rp3);
+        spl.remove(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp3), rp3.getProperties()));
+        check(spl, ctx);
+    }
+
+    @Test public void testSortingRF() {
+        final AdaptableResourceProviderImpl rp1 = new AdaptableResourceProviderImpl(new String[] {"/d", "/a", "x"}, 1L);
+        final AdaptableResourceProviderImpl rp2 = new AdaptableResourceProviderImpl(null, 2L);
+        final AdaptableResourceProviderImpl rp3 = new AdaptableResourceProviderImpl(new String[] {"/b"}, 3L);
+        final AdaptableResourceProviderImpl rp4 = new AdaptableResourceProviderImpl(new String[] {"/a/a"}, 4L);
+        final AdaptableResourceProviderImpl rp5 = new AdaptableResourceProviderImpl(new String[] {"/all/or/nothing"}, 5L);
+
+        final ResourceResolverContext ctx = new ResourceResolverContext(false, null);
+
+        final SortedProviderList<Adaptable> spl = new SortedProviderList<Adaptable>(Adaptable.class);
+        check(spl, ctx);
+        spl.add(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp1), rp1.getProperties()));
+        check(spl, ctx, rp1);
+        spl.add(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp2), rp2.getProperties()));
+        check(spl, ctx, rp2, rp1);
+        spl.add(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp3), rp3.getProperties()));
+        check(spl, ctx, rp2, rp1, rp3);
+        spl.add(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp4), rp4.getProperties()));
+        check(spl, ctx, rp2, rp1, rp4, rp3);
+        spl.add(new ResourceProviderFactoryHandler(new ResourceProviderFactoryImpl(rp5), rp5.getProperties()));
+        check(spl, ctx, rp2, rp1, rp4, rp5, rp3);
+    }
+
+    @Test public void checkExceptions() {
+        final AdaptableResourceProviderImpl rp2 = new AdaptableResourceProviderImpl(null, 2L);
+
+        final SortedProviderList<Adaptable> spl = new SortedProviderList<Adaptable>(Adaptable.class);
+        spl.add(new ResourceProviderHandler(rp2, rp2.getProperties()));
+
+        final Iterator<Adaptable> i = spl.getProviders(null);
+        assertTrue(i.hasNext());
+        i.next(); // one entry
+        assertFalse(i.hasNext());
+        try {
+            i.remove();
+            fail();
+        } catch (UnsupportedOperationException uoe) {
+            // expected
+        }
+        try {
+            i.next();
+            fail();
+        } catch (NoSuchElementException nsee) {
+            // expected
+        }
+        assertFalse(i.hasNext());
+    }
+
+    /**
+     * Helper method checking the order of the sorted array.
+     */
+    private void check(final SortedProviderList<Adaptable> spl,
+                    final ResourceResolverContext ctx,
+                    final Adaptable... objects) {
+        final int expectedCount = objects == null ? 0 : objects.length;
+        final Iterator<Adaptable> i = spl.getProviders(ctx);
+        int count = 0;
+        while ( i.hasNext() ) {
+            final Adaptable a = i.next();
+            assertEquals(objects[count], a);
+            count++;
+        }
+        assertEquals(expectedCount, count);
+    }
+
+    private static class ResourceProviderImpl implements ResourceProvider {
+
+        private final String[] roots;
+        private final Long serviceId;
+
+        public ResourceProviderImpl(String[] roots, Long serviceId) {
+            this.roots = roots;
+            this.serviceId = serviceId;
+        }
+
+        public Map<String, Object> getProperties() {
+            final Map<String, Object> props = new HashMap<String, Object>();
+            props.put(Constants.SERVICE_ID, serviceId);
+            props.put(ResourceProvider.ROOTS, roots);
+            return props;
+        }
+
+        public Resource getResource(ResourceResolver resourceResolver, HttpServletRequest request, String path) {
+            return null;
+        }
+
+        public Resource getResource(ResourceResolver resourceResolver, String path) {
+            return null;
+        }
+
+        public Iterator<Resource> listChildren(Resource parent) {
+            return null;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if ( obj instanceof ResourceProviderImpl ) {
+                return this.serviceId.equals(((ResourceProviderImpl)obj).serviceId);
+            }
+            return false;
+        }
+    }
+
+    private static class AdaptableResourceProviderImpl extends ResourceProviderImpl
+    implements Adaptable {
+
+        public AdaptableResourceProviderImpl(String[] roots, Long serviceId) {
+            super(roots, serviceId);
+        }
+
+        public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+            return null;
+        }
+    }
+
+    private static class ResourceProviderFactoryImpl implements ResourceProviderFactory {
+
+        private final ResourceProviderImpl resourceProviderImpl;
+
+        public ResourceProviderFactoryImpl(ResourceProviderImpl rpi) {
+            this.resourceProviderImpl = rpi;
+        }
+
+        public ResourceProvider getResourceProvider(Map<String, Object> authenticationInfo) throws LoginException {
+            return this.resourceProviderImpl;
+        }
+
+        public ResourceProvider getAdministrativeResourceProvider(Map<String, Object> authenticationInfo) throws LoginException {
+            return this.resourceProviderImpl;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if ( obj instanceof ResourceProviderFactoryImpl ) {
+                return this.resourceProviderImpl.equals(((ResourceProviderFactoryImpl)obj).resourceProviderImpl);
+            }
+            return false;
+        }
+    }
+}

Propchange: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/SortedProviderListTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/SortedProviderListTest.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url

Added: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/StarResourceTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/StarResourceTest.java?rev=1350169&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/StarResourceTest.java (added)
+++ sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/StarResourceTest.java Thu Jun 14 09:52:08 2012
@@ -0,0 +1,50 @@
+/*
+ * 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.helper;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.sling.api.resource.ResourceMetadata;
+import org.junit.Test;
+
+/** Test the StarResource */
+public class StarResourceTest {
+
+	private void assertSplit(String requestPath, String path, String pathInfo) {
+		final ResourceMetadata rm = StarResource.getResourceMetadata(requestPath);
+		assertEquals("For requestPath=" + requestPath + ", path matches", path, rm.getResolutionPath());
+		assertEquals("For requestPath=" + requestPath + ", pathInfo matches", pathInfo, rm.getResolutionPathInfo());
+	}
+
+	@Test public void testSimplePath() {
+		assertSplit("/foo/*.html", "/foo/*", ".html");
+	}
+
+	@Test public void testNoExtension() {
+		assertSplit("/foo/*", "/foo/*", "");
+	}
+
+	@Test public void testNoStar() {
+		assertSplit("/foo/bar.html", "/foo/bar.html", null);
+	}
+
+	@Test public void testTwoStars() {
+		assertSplit("/foo/*.html/*.txt", "/foo/*", ".html/*.txt");
+	}
+}

Propchange: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/StarResourceTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/helper/StarResourceTest.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision rev url



Mime
View raw message