You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ie...@apache.org on 2009/10/16 00:05:40 UTC
svn commit: r825678 - in /sling/trunk/contrib/jcr/resource2: ./
src/main/java/org/apache/sling/jcr/resource/internal/
src/main/java/org/apache/sling/jcr/resource/internal/helper/
src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/ src/test...
Author: ieb
Date: Thu Oct 15 22:05:39 2009
New Revision: 825678
URL: http://svn.apache.org/viewvc?rev=825678&view=rev
Log:
SLING-1156
Patched the ResourceProviderEntry into ResourceProviderEntry2 to create a Tree of Maps for resolution.
Added:
sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntry2.java (with props)
Modified:
sling/trunk/contrib/jcr/resource2/pom.xml
sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2.java
sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java
sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderEntry.java
sling/trunk/contrib/jcr/resource2/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2Test.java
sling/trunk/contrib/jcr/resource2/src/test/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntryTest.java
Modified: sling/trunk/contrib/jcr/resource2/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/jcr/resource2/pom.xml?rev=825678&r1=825677&r2=825678&view=diff
==============================================================================
--- sling/trunk/contrib/jcr/resource2/pom.xml (original)
+++ sling/trunk/contrib/jcr/resource2/pom.xml Thu Oct 15 22:05:39 2009
@@ -26,11 +26,11 @@
<relativePath>../../../parent/pom.xml</relativePath>
</parent>
- <artifactId>org.apache.sling.jcr.resource</artifactId>
+ <artifactId>org.apache.sling.jcr.resource2</artifactId>
<version>2.0.7-SNAPSHOT</version>
<packaging>bundle</packaging>
- <name>Apache Sling Resource Resolver</name>
+ <name>Apache Sling Resource Resolver (Tree of Maps)</name>
<description>
This bundle provides the JCR based ResourceResolver.
</description>
Modified: sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2.java?rev=825678&r1=825677&r2=825678&view=diff
==============================================================================
--- sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2.java (original)
+++ sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2.java Thu Oct 15 22:05:39 2009
@@ -92,6 +92,7 @@
public JcrResourceResolver2(JcrResourceProviderEntry rootProvider,
JcrResourceResolverFactoryImpl factory, MapEntries resourceMapper) {
+
this.rootProvider = rootProvider;
this.factory = factory;
this.resourceMapper = resourceMapper;
Modified: sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java?rev=825678&r1=825677&r2=825678&view=diff
==============================================================================
--- sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java (original)
+++ sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java Thu Oct 15 22:05:39 2009
@@ -32,6 +32,7 @@
import org.apache.commons.collections.BidiMap;
import org.apache.commons.collections.bidimap.TreeBidiMap;
+import org.apache.jackrabbit.name.Path.RootElement;
import org.apache.sling.api.SlingConstants;
import org.apache.sling.api.resource.ResourceProvider;
import org.apache.sling.api.resource.ResourceResolver;
@@ -42,8 +43,7 @@
import org.apache.sling.jcr.resource.JcrResourceTypeProvider;
import org.apache.sling.jcr.resource.internal.helper.MapEntries;
import org.apache.sling.jcr.resource.internal.helper.Mapping;
-import org.apache.sling.jcr.resource.internal.helper.ResourceProviderEntry;
-import org.apache.sling.jcr.resource.internal.helper.ResourceProviderEntryException;
+import org.apache.sling.jcr.resource.internal.helper.ResourceProviderEntry2;
import org.apache.sling.jcr.resource.internal.helper.jcr.JcrResourceProviderEntry;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
@@ -194,7 +194,7 @@
// the search path for ResourceResolver.getResource(String)
private String[] searchPath;
- private ResourceProviderEntry rootProviderEntry;
+ private ResourceProviderEntry2 rootProviderEntry;
// whether to mangle paths with namespaces or not
private boolean mangleNamespacePrefixes;
@@ -211,7 +211,8 @@
private DynamicClassLoaderManager dynamicClassLoaderManager;
public JcrResourceResolverFactoryImpl() {
- this.rootProviderEntry = new ResourceProviderEntry("/", null, null);
+ this.rootProviderEntry = new ResourceProviderEntry2("/", null);
+
}
// ---------- JcrResourceResolverFactory -----------------------------------
@@ -224,6 +225,7 @@
JcrResourceProviderEntry sessionRoot = new JcrResourceProviderEntry(
session, rootProviderEntry, getJcrResourceTypeProviders(),
this.getDynamicClassLoader());
+
return new JcrResourceResolver2(sessionRoot, this, mapEntries);
}
@@ -288,7 +290,7 @@
*
* @return Our rootProviderEntry
*/
- protected ResourceProviderEntry getRootProviderEntry() {
+ protected ResourceProviderEntry2 getRootProviderEntry() {
return rootProviderEntry;
}
@@ -480,23 +482,16 @@
root = root.substring(0, root.length() - 1);
}
- try {
- rootProviderEntry.addResourceProvider(root,
- provider);
-
- log.debug("bindResourceProvider: {}={} ({})",
- new Object[] { root, provider, serviceName });
- if ( localEA != null ) {
- final Dictionary<String, Object> props = new Hashtable<String, Object>();
- props.put(SlingConstants.PROPERTY_PATH, root);
- localEA.postEvent(new Event(SlingConstants.TOPIC_RESOURCE_PROVIDER_ADDED,
- props));
- }
- } catch (ResourceProviderEntryException rpee) {
- log.error(
- "bindResourceProvider: Cannot register ResourceProvider {} for {}: ResourceProvider {} is already registered",
- new Object[] { provider, root,
- rpee.getExisting().getResourceProvider() });
+ rootProviderEntry.addResourceProvider(root,
+ provider);
+
+ log.debug("bindResourceProvider: {}={} ({})",
+ new Object[] { root, provider, serviceName });
+ if ( localEA != null ) {
+ final Dictionary<String, Object> props = new Hashtable<String, Object>();
+ props.put(SlingConstants.PROPERTY_PATH, root);
+ localEA.postEvent(new Event(SlingConstants.TOPIC_RESOURCE_PROVIDER_ADDED,
+ props));
}
}
}
@@ -520,6 +515,10 @@
// synchronized insertion of new resource providers into
// the tree to not inadvertently loose an entry
synchronized (this) {
+ if ( componentContext != null ) {
+ ResourceProvider provider = (ResourceProvider) componentContext.locateService(
+ "ResourceProvider", reference);
+
for (String root : roots) {
// cut off trailing slash
@@ -530,7 +529,7 @@
// TODO: Do not remove this path, if another resource
// owns it. This may be the case if adding the provider
// yielded an ResourceProviderEntryException
- rootProviderEntry.removeResourceProvider(root);
+ rootProviderEntry.removeResourceProvider(root, provider);
log.debug("unbindResourceProvider: root={} ({})", root,
serviceName);
@@ -541,6 +540,7 @@
props));
}
}
+ }
}
}
@@ -626,4 +626,12 @@
return null;
}
+
+
+ public void run() {
+ String stat = rootProviderEntry.getResolutionStats();
+ if ( stat != null ) {
+ log.info(stat);
+ }
+ }
}
Added: sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntry2.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntry2.java?rev=825678&view=auto
==============================================================================
--- sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntry2.java (added)
+++ sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntry2.java Thu Oct 15 22:05:39 2009
@@ -0,0 +1,641 @@
+/*
+ * 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.jcr.resource.internal.helper;
+
+import org.apache.commons.collections.FastTreeMap;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceProvider;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.SyntheticResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+/**
+ * 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.
+ */
+public class ResourceProviderEntry2 implements
+ Comparable<ResourceProviderEntry2> {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 7420631325909144862L;
+
+ private static Logger LOGGER = LoggerFactory.getLogger(ResourceProviderEntry2.class);
+
+ // the path to resources provided by the resource provider of this
+ // entry. this path is relative to the path of the parent resource
+ // provider entry and has no trailing slash.
+ private final String path;
+
+ // the path to resources provided by the resource provider of this
+ // entry. this is the same path as the path field but with a trailing
+ // slash to be used as a prefix match resource paths to resolve
+ private final String prefix;
+
+ // the resource provider kept in this entry supporting resources at and
+ // below the path of this entry.
+ private ResourceProvider[] providers = new ResourceProvider[0];
+
+ private long ttime = 0L;
+
+ private long nmiss = 0L;
+
+ private long nsynthetic = 0L;
+
+ private long nreal = 0L;
+
+ private FastTreeMap storageMap = new FastTreeMap();
+
+ /**
+ * Creates an instance of this class with the given path relative to the
+ * parent resource provider entry, encapsulating the given ResourceProvider,
+ * and a number of inital child entries.
+ *
+ * @param path
+ * The relative path supported by the provider
+ * @param provider
+ * The resource provider to encapsulate by this entry.
+ */
+ public ResourceProviderEntry2(String path, ResourceProvider[] provider) {
+ if (path.endsWith("/")) {
+ this.path = path.substring(0, path.length() - 1);
+ this.prefix = path;
+ } else {
+ this.path = path;
+ this.prefix = path + "/";
+ }
+ this.providers = provider;
+
+ // this will consume slightly more memory but ensures read is fast.
+ storageMap.setFast(true);
+ }
+
+ /**
+ * Returns the resource provider contained in this entry
+ */
+ public ResourceProvider[] getResourceProviders() {
+ return providers;
+ }
+
+ /**
+ * Returns the resource with the given path or <code>null</code> if neither
+ * the resource provider of this entry nor the resource provider of any of
+ * the child entries can provide the resource.
+ *
+ * @param path
+ * The path to the resource to return.
+ * @return The resource for the path or <code>null</code> if no resource can
+ * be found.
+ * @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 Iterator<Resource> listChildren(final Resource resource) {
+ LOGGER.debug("Child Iterator for {}",resource.getPath());
+ return new Iterator<Resource>() {
+ private final Iterator<ResourceProvider> providers;
+
+ private Iterator<Resource> resources;
+
+ private Resource nextResource;
+
+ private Map<String, Resource> delayed;
+
+ private Set<String> visited;
+
+ private Iterator<Resource> delayedIter;
+
+ {
+ String path = resource.getPath();
+ if (!path.endsWith("/")) {
+ path += "/";
+ }
+
+ // gather the providers in linked set, such that we keep
+ // the order of addition and make sure we only get one entry
+ // for each resource provider
+ Set<ResourceProvider> providersSet = new LinkedHashSet<ResourceProvider>();
+ getResourceProviders(path, providersSet);
+
+ LOGGER.debug(" Provider Set for path {} {} ",path,Arrays.toString(providersSet.toArray(new ResourceProvider[0])));
+
+ providers = providersSet.iterator();
+ delayed = new HashMap<String, Resource>();
+ visited = new HashSet<String>();
+ nextResource = seek();
+ }
+
+ public boolean hasNext() {
+ return nextResource != null;
+ }
+
+ public Resource next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+
+ Resource result = nextResource;
+ nextResource = seek();
+ LOGGER.debug(" Child Resoruce {} ", result.getPath());
+ return result;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("remove");
+ }
+
+ private Resource seek() {
+ for (;;) {
+ while ((resources == null || !resources.hasNext())
+ && providers.hasNext()) {
+ ResourceProvider provider = providers.next();
+ resources = provider.listChildren(resource);
+ LOGGER.debug(" Checking Provider {} ", provider);
+ }
+
+ if (resources != null && resources.hasNext()) {
+ Resource res = resources.next();
+ String resPath = res.getPath();
+ LOGGER.debug(" resource {} ", res.getPath());
+
+ if (visited.contains(resPath)) {
+
+ // ignore a path, we have already visited and
+ // ensure it will not be listed as a delayed
+ // resource at the end
+ delayed.remove(resPath);
+
+ } else if (res instanceof SyntheticResource) {
+
+ // don't return synthetic resources right away,
+ // since a concrete resource for the same path
+ // may be provided later on
+ delayed.put(resPath, res);
+
+ } else {
+
+ // we use this concrete, unvisited resource but
+ // mark it as visited
+ visited.add(resPath);
+ return res;
+
+ }
+ } else {
+ break;
+ }
+ }
+
+ // we exhausted all resource providers with their concrete
+ // resources. now lets do the delayed (synthetic) resources
+ if (delayedIter == null) {
+ delayedIter = delayed.values().iterator();
+ }
+ Resource res = delayedIter.hasNext() ? delayedIter.next() : null;
+ if ( res != null ) {
+ LOGGER.debug(" D resource {} ", res.getPath());
+ }
+ return res;
+ }
+ };
+ }
+
+ /**
+ * Adds the given resource provider into the tree for the given prefix.
+ *
+ * @return <code>true</code> if the provider could be entered into the
+ * subtree below this entry. Otherwise <code>false</code> is
+ * returned.
+ */
+ public boolean addResourceProvider(String prefix, ResourceProvider provider) {
+ synchronized (this) {
+ String[] elements = split(prefix, '/');
+ List<ResourceProviderEntry2> entryPath = getResourceProviderPath(elements);
+ entryPath.add(this); // add this to the end
+ // I want to add to the end, but remember the list of entries starts
+ // with the root.
+ Collections.reverse(entryPath);
+ for (int i = entryPath.size() - 1; i < elements.length; i++) {
+ String stubPrefix = elements[i];
+ ResourceProviderEntry2 rpe2 = new ResourceProviderEntry2(
+ stubPrefix, new ResourceProvider[0]);
+ entryPath.get(i).put(elements[i], rpe2);
+ entryPath.add(rpe2);
+ }
+ return entryPath.get(elements.length).addInternalProvider(provider);
+
+ }
+ }
+
+
+ //------------------ Map methods, here so that we can delegate 2 maps together
+ /**
+ * @param string
+ * @param rpe2
+ */
+ public void put(String key, ResourceProviderEntry2 value) {
+ storageMap.put(key,value);
+ }
+
+ /**
+ * @param element
+ * @return
+ */
+ public boolean containsKey(String key) {
+ return storageMap.containsKey(key);
+ }
+
+
+ /**
+ * @param element
+ * @return
+ */
+ public ResourceProviderEntry2 get(String key) {
+ return (ResourceProviderEntry2) storageMap.get(key);
+ }
+
+ /**
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ public Collection<ResourceProviderEntry2> values() {
+ return storageMap.values();
+ }
+
+ public boolean removeResourceProvider(String prefix,
+ ResourceProvider provider) {
+ synchronized (this) {
+ String[] elements = split(prefix, '/');
+ List<ResourceProviderEntry2> entryPath = getResourceProviderPath(elements);
+ if (entryPath.size() == elements.length) {
+ // the first element is a perfect match;
+ return entryPath.get(0).removeInternalProvider(provider);
+ }
+ return false;
+ }
+ }
+
+ // ---------- Comparable<ResourceProviderEntry> interface ------------------
+
+ public int compareTo(ResourceProviderEntry2 o) {
+ return prefix.compareTo(o.prefix);
+ }
+
+ // ---------- internal -----------------------------------------------------
+
+ /**
+ * Adds a list of providers to this entry.
+ *
+ * @param provider
+ */
+ private boolean addInternalProvider(ResourceProvider provider) {
+ synchronized (providers) {
+ int before = providers.length;
+ Set<ResourceProvider> set = new HashSet<ResourceProvider>();
+ if (providers != null) {
+ set.addAll(Arrays.asList(providers));
+ }
+ set.add(provider);
+ providers = conditionalSort(set);
+ return providers.length > before;
+ }
+
+ }
+
+ /**
+ * @param provider
+ * @return
+ */
+ private boolean removeInternalProvider(ResourceProvider provider) {
+ synchronized (providers) {
+ int before = providers.length;
+ Set<ResourceProvider> set = new HashSet<ResourceProvider>();
+ if (providers != null) {
+ set.addAll(Arrays.asList(providers));
+ }
+ set.remove(provider);
+ providers = conditionalSort(set);
+ return providers.length < before;
+ }
+ }
+
+ /**
+ * @param set
+ * @return
+ */
+ private ResourceProvider[] conditionalSort(Set<ResourceProvider> set) {
+ //
+ // convert to a list so we can selectively sort. We can't guarantee that
+ // all
+ // ResourceProviders implement Comparable so can't use a TreeSet.
+ // However, using a set in the first instance ensures that no one relies
+ // on the add
+ // order.
+
+ List<ResourceProvider> providerList = new ArrayList<ResourceProvider>(
+ set);
+ // ResourceProviders that need to get into the list ahead of others must
+ // implement
+ // the comparable interface. Ones that don't implement the comparable
+ // interface get
+ // placed in a group in the center ordered by the way they were added.
+ // eg high-priority ..... non conflicting .... explicitly low priority
+ // In general if a ResourceProvider will only ever respond with non null
+ // to paths
+ // that no other resource provider will respond with non null its non
+ // conflicting and
+ // so does not require special treatment (eg no Comparable required)
+
+ Collections.sort(providerList, new Comparator<ResourceProvider>() {
+
+ @SuppressWarnings("unchecked")
+ public int compare(ResourceProvider o1, ResourceProvider o2) {
+ if (o1 instanceof Comparable) {
+ Comparable c1 = (Comparable) o1;
+ return c1.compareTo(o2);
+ } else if (o2 instanceof Comparable) {
+ Comparable c2 = (Comparable) o2;
+ return c2.compareTo(o1) * (-1);
+ }
+ return 0;
+ }
+ });
+
+ return set.toArray(new ResourceProvider[set.size()]);
+ }
+
+ /**
+ * Get a of ResourceProvidersEntries leading to the fullPath in reverse
+ * order.
+ *
+ * @param fullPath
+ * the full path
+ * @return a reverse order list of ProviderEntries to the path.
+ */
+ private List<ResourceProviderEntry2> getResourceProviderPath(
+ String[] elements) {
+ ResourceProviderEntry2 base = this;
+ List<ResourceProviderEntry2> providerEntryPath = new ArrayList<ResourceProviderEntry2>();
+ if (elements != null) {
+ for (String element : elements) {
+ if (element != null) {
+ if (base.containsKey(element)) {
+ base = base.get(element);
+ providerEntryPath.add(base);
+ } else {
+ break;
+ }
+ }
+ }
+ Collections.reverse(providerEntryPath);
+ }
+ return providerEntryPath;
+ }
+
+
+ /**
+ * Resolve a resource from a path into a Resource
+ *
+ * @param resolver
+ * the ResourceResolver.
+ * @param fullPath
+ * 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();
+ try {
+
+ if (fullPath == null || fullPath.length() == 0
+ || fullPath.charAt(0) != '/') {
+ nmiss++;
+ LOGGER.debug("Not absolute {} :{}",fullPath,(System.currentTimeMillis() - start));
+ return null; // fullpath must be absolute
+ }
+ String[] elements = split(fullPath, '/'); // should use something
+ // more efficient here.
+ List<ResourceProviderEntry2> list = getResourceProviderPath(elements);
+ // the path is in reverse order end first
+
+ int i = 0;
+ for (ResourceProviderEntry2 rpe : list) {
+ ResourceProvider[] rps = rpe.getResourceProviders();
+ int j = 0;
+ for (ResourceProvider rp : rps) {
+
+ Resource resource = rp.getResource(resourceResolver,
+ fullPath);
+ if (resource != null) {
+ nreal++;
+ LOGGER.debug("Resolved Full {} using {} from {} ",new Object[]{
+ fullPath, rp, Arrays.toString(rps)});
+ return resource;
+ }
+ j++;
+ }
+ i++;
+ }
+ // query: /libs/sling/servlet/default
+ // 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 (element 0)
+ if (list.size() > 0 && list.size() == elements.length ) {
+ if ( list.get(0).getResourceProviders().length == 0 ) {
+ nsynthetic++;
+ LOGGER.debug("Resolved Synthetic {}", fullPath);
+ return new SyntheticResource(resourceResolver,
+ fullPath,
+ ResourceProvider.RESOURCE_TYPE_SYNTHETIC);
+ }
+ }
+
+ // resolve against this one
+ ResourceProvider[] rps = getResourceProviders();
+ int j = 0;
+ for (ResourceProvider rp : rps) {
+ Resource resource = rp.getResource(resourceResolver, fullPath);
+ if (resource != null) {
+ nreal++;
+ LOGGER.debug("Resolved Base {} using {} ", fullPath, rp);
+ return resource;
+ }
+ j++;
+ }
+
+
+ LOGGER.debug("Resource null {} ", fullPath);
+ nmiss++;
+ return null;
+ } catch (Exception ex) {
+ LOGGER.debug("Failed! ",ex);
+ return null;
+ } finally {
+ ttime += System.currentTimeMillis() - start;
+ }
+ }
+
+
+ /**
+ * Returns all resource providers which provider resources whose prefix is
+ * the given path.
+ *
+ * @param path
+ * The prefix path to match the resource provider roots against
+ * @param providers
+ * The set of already found resource providers to which any
+ * additional resource providers are added.
+ */
+ private void getResourceProviders(String path,
+ Set<ResourceProvider> providers) {
+ String[] elements = split(path, '/');
+ ResourceProviderEntry2 base = this;
+ for (String element : elements ) {
+ if ( base.containsKey(element)) {
+ base = base.get(element);
+ } else {
+ base = null;
+ break;
+ }
+ }
+ // the path has been exausted and there is a subtree to be collected, so go and collect it.
+ if ( base != null ) {
+ getResourceProviders(base, providers);
+ }
+ // add in providers at this node in the tree, ie the root provider
+ for ( ResourceProvider rp : getResourceProviders() ) {
+ providers.add(rp);
+ }
+
+ }
+
+ /**
+ * @param base
+ * @param providers2
+ */
+ private void getResourceProviders(ResourceProviderEntry2 entry,
+ Set<ResourceProvider> providers) {
+ // recurse down the tree
+ LOGGER.debug(" Gathering For {} ",entry.prefix);
+ for ( ResourceProviderEntry2 e : entry.values() ) {
+ getResourceProviders(e, providers);
+ }
+ // add in providers at this node in the tree.
+ for ( ResourceProvider rp : entry.getResourceProviders() ) {
+ providers.add(rp);
+ }
+ }
+
+ /**
+ * @param st
+ * @param sep
+ * @return an array of the strings between the separator
+ */
+ private String[] split(String st, char sep) {
+
+ if (st == null) {
+ return new String[0];
+ }
+ char[] pn = st.toCharArray();
+ if (pn.length == 0) {
+ return new String[0];
+ }
+ if (pn.length == 1 && pn[0] == sep) {
+ return new String[0];
+ }
+ int n = 1;
+ int start = 0;
+ int end = pn.length;
+ while (start < end && sep == pn[start])
+ start++;
+ while (start < end && sep == pn[end - 1])
+ end--;
+ for (int i = start; i < end; i++) {
+ if (sep == pn[i]) {
+ n++;
+ }
+ }
+ String[] e = new String[n];
+ int s = start;
+ int j = 0;
+ for (int i = start; i < end; i++) {
+ if (pn[i] == sep) {
+ e[j++] = new String(pn, s, i - s);
+ s = i + 1;
+ }
+ }
+ if (s < end) {
+ e[j++] = new String(pn, s, end - s);
+ }
+ return e;
+ }
+
+ /**
+ * @return
+ */
+ public String getResolutionStats() {
+ 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";
+ ttime = nmiss = nsynthetic = nreal = 0L;
+ return stat;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see java.util.AbstractMap#toString()
+ */
+ @Override
+ public String toString() {
+ return this.path;
+ //"{path:\"" + this.path + "\", providers:"+Arrays.toString(getResourceProviders())+", map:" + storageMap.toString() + "}";
+ }
+
+}
Propchange: sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntry2.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderEntry.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderEntry.java?rev=825678&r1=825677&r2=825678&view=diff
==============================================================================
--- sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderEntry.java (original)
+++ sling/trunk/contrib/jcr/resource2/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProviderEntry.java Thu Oct 15 22:05:39 2009
@@ -22,21 +22,31 @@
import org.apache.sling.api.resource.ResourceProvider;
import org.apache.sling.jcr.resource.JcrResourceTypeProvider;
-import org.apache.sling.jcr.resource.internal.helper.ResourceProviderEntry;
+import org.apache.sling.jcr.resource.internal.helper.ResourceProviderEntry2;
-public class JcrResourceProviderEntry extends ResourceProviderEntry {
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
- private final ResourceProviderEntry delegatee;
+public class JcrResourceProviderEntry extends ResourceProviderEntry2 {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 5672648586247261128L;
+
+ private final ResourceProviderEntry2 delegatee;
private final Session session;
private final JcrResourceTypeProvider[] resourceTypeProviders;
public JcrResourceProviderEntry(Session session,
- ResourceProviderEntry delegatee,
- JcrResourceTypeProvider[] resourceTypeProviders,
- final ClassLoader dynamicClassLoader) {
- super("/", new JcrResourceProvider(session, resourceTypeProviders, dynamicClassLoader), null);
+ ResourceProviderEntry2 delegatee,
+ JcrResourceTypeProvider[] resourceTypeProviders,
+ final ClassLoader dynamicClassLoader) {
+ super("/", new ResourceProvider[] { new JcrResourceProvider(session,
+ resourceTypeProviders, dynamicClassLoader) });
this.delegatee = delegatee;
this.session = session;
@@ -52,17 +62,99 @@
}
@Override
- public ResourceProviderEntry[] getEntries() {
- return delegatee.getEntries();
+ public boolean addResourceProvider(String prefix, ResourceProvider provider) {
+ return delegatee.addResourceProvider(prefix, provider);
}
@Override
- public boolean addResourceProvider(String prefix, ResourceProvider provider) {
- return delegatee.addResourceProvider(prefix, provider);
+ public boolean removeResourceProvider(String prefix,
+ ResourceProvider provider) {
+ return delegatee.removeResourceProvider(prefix, provider);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.apache.sling.jcr.resource.internal.helper.ResourceProviderEntry2#put(java.lang.String,
+ * org.apache.sling.jcr.resource.internal.helper.ResourceProviderEntry2)
+ */
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.apache.sling.jcr.resource.internal.helper.ResourceProviderEntry2#get(java.lang.String)
+ */
+ @Override
+ public ResourceProviderEntry2 get(String key) {
+ ResourceProviderEntry2 rpe = super.get(key);
+ if (rpe == null) {
+ rpe = delegatee.get(key);
+ }
+ return rpe;
}
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.apache.sling.jcr.resource.internal.helper.ResourceProviderEntry2#values()
+ */
@Override
- public boolean removeResourceProvider(String prefix) {
- return delegatee.removeResourceProvider(prefix);
+ public Collection<ResourceProviderEntry2> values() {
+ List<ResourceProviderEntry2> list = new ArrayList<ResourceProviderEntry2>(
+ super.values());
+ list.addAll(delegatee.values());
+ return list;
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.apache.sling.jcr.resource.internal.helper.ResourceProviderEntry2#containsKey(java.lang.String)
+ */
+ @Override
+ public boolean containsKey(String key) {
+ return (super.containsKey(key) || delegatee.containsKey(key));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.apache.sling.jcr.resource.internal.helper.ResourceProviderEntry#getResourceProviders()
+ */
+ @Override
+ public ResourceProvider[] getResourceProviders() {
+ // merge the delegatee and this set of providers,
+ // its probably better to do this every time, as
+
+ ResourceProvider[] delegateeProviders = delegatee
+ .getResourceProviders();
+ ResourceProvider[] superProviders = super.getResourceProviders();
+ if (delegateeProviders == null && superProviders == null) {
+ return null;
+ }
+ if (delegateeProviders == null) {
+ delegateeProviders = new ResourceProvider[0];
+ }
+ if (superProviders == null) {
+ superProviders = new ResourceProvider[0];
+ }
+ ResourceProvider[] resourceProviders = new ResourceProvider[delegateeProviders.length
+ + superProviders.length];
+ System.arraycopy(delegateeProviders, 0, resourceProviders, 0,
+ delegateeProviders.length);
+ System.arraycopy(superProviders, 0, resourceProviders,
+ delegateeProviders.length, superProviders.length);
+ return resourceProviders;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.apache.sling.jcr.resource.internal.helper.ResourceProviderEntry2#toString()
+ */
+ @Override
+ public String toString() {
+ return delegatee.toString();
+ }
+
}
Modified: sling/trunk/contrib/jcr/resource2/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2Test.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/jcr/resource2/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2Test.java?rev=825678&r1=825677&r2=825678&view=diff
==============================================================================
--- sling/trunk/contrib/jcr/resource2/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2Test.java (original)
+++ sling/trunk/contrib/jcr/resource2/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2Test.java Thu Oct 15 22:05:39 2009
@@ -144,6 +144,7 @@
super.tearDown();
}
+ @SuppressWarnings("deprecation")
public void testBasicAPIAssumptions() throws Exception {
// null resource is accessing /, which exists of course
@@ -195,7 +196,7 @@
final HttpServletRequest req2 = new ResourceResolverTestRequest(null);
final Resource res2 = resResolver.resolve(req2);
assertNotNull("Expecting resource if resolution fails", res2);
- assertTrue("Resource must not be NonExistingResource",
+ assertTrue("Resource must not be NonExistingResource was ",
!(res2 instanceof NonExistingResource));
assertEquals("Path must be the the root path", "/", res2.getPath());
}
Modified: sling/trunk/contrib/jcr/resource2/src/test/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntryTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/contrib/jcr/resource2/src/test/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntryTest.java?rev=825678&r1=825677&r2=825678&view=diff
==============================================================================
--- sling/trunk/contrib/jcr/resource2/src/test/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntryTest.java (original)
+++ sling/trunk/contrib/jcr/resource2/src/test/java/org/apache/sling/jcr/resource/internal/helper/ResourceProviderEntryTest.java Thu Oct 15 22:05:39 2009
@@ -18,6 +18,7 @@
*/
package org.apache.sling.jcr.resource.internal.helper;
+import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
@@ -25,23 +26,25 @@
import junit.framework.TestCase;
+import org.apache.sling.api.resource.NonExistingResource;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceMetadata;
import org.apache.sling.api.resource.ResourceProvider;
import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.SyntheticResource;
public class ResourceProviderEntryTest extends TestCase {
private ResourceProvider rootProvider;
- private ResourceProviderEntry root;
+ private ResourceProviderEntry2 root;
@Override
protected void setUp() throws Exception {
super.setUp();
rootProvider = new TestResourceProvider("/");
- root = new ResourceProviderEntry("/", rootProvider, null);
+ root = new ResourceProviderEntry2("/", new ResourceProvider[]{ rootProvider});
}
@Override
@@ -63,6 +66,7 @@
String firstPath = "/rootel";
ResourceProvider first = new TestResourceProvider(firstPath);
root.addResourceProvider(firstPath, first);
+
assertEquals(root, root.getResource(null, "/"));
assertEquals(first, root.getResource(null, "/rootel"));
@@ -88,6 +92,8 @@
root.addResourceProvider(secondPath, second);
root.addResourceProvider(thirdPath, third);
+
+
assertEquals(rootProvider, root.getResource(null, "/"));
assertEquals(first, root.getResource(null, "/rootel"));
assertEquals(first, root.getResource(null, "/rootel/html.js"));
@@ -95,8 +101,9 @@
assertEquals(second, root.getResource(null, "/rootel/child/html.js"));
assertEquals(third,
root.getResource(null, "/apps/sling/sample/html.js"));
- assertEquals(rootProvider, root.getResource(null,
- "/apps/sling/microsling/html.js"));
+ Resource resource = root.getResource(null,
+ "/apps/sling/microsling/html.js");
+ assertEquals(rootProvider, resource);
}
public void testAdd3ProvidersReverse() {
@@ -118,9 +125,10 @@
assertEquals(second, root.getResource(null, "/rootel/child"));
assertEquals(second, root.getResource(null, "/rootel/child/html.js"));
assertEquals(third,
- root.getResource(null, "/apps/sling/sample/html.js"));
- assertEquals(rootProvider, root.getResource(null,
- "/apps/sling/microsling/html.js"));
+ root.getResource(null, "/apps/sling/sample/html.js"));
+ Resource resource = root.getResource(null,
+ "/apps/sling/microsling/html.js");
+ assertEquals(rootProvider, resource);
}
public void testRemoveProviders() {
@@ -140,9 +148,11 @@
assertEquals(first, root.getResource(null, "/rootel/html.js"));
assertEquals(second, root.getResource(null, "/rootel/child/html.js"));
- root.removeResourceProvider(firstPath);
+ root.removeResourceProvider(firstPath, first);
+
assertEquals(rootProvider, root.getResource(null, "/"));
+ assertEquals(rootProvider, root.getResource(null, "/rootel/sddsf/sdfsdf/html.js"));
assertEquals(rootProvider, root.getResource(null, "/rootel/html.js"));
assertEquals(second, root.getResource(null, "/rootel/child/html.js"));
@@ -150,17 +160,22 @@
assertEquals(rootProvider, root.getResource(null, "/"));
assertEquals(first, root.getResource(null, "/rootel/html.js"));
- assertEquals(second, root.getResource(null, "/rootel/child/html.js"));
+ assertEquals(second,root.getResource(null, "/rootel/child/html.js"));
}
protected void assertEquals(ResourceProvider resProvider, Resource res) {
assertEquals(resProvider, res.getResourceResolver());
}
- protected void assertEquals(ResourceProviderEntry resProviderEntry,
+ protected void assertEquals(ResourceProviderEntry2 resProviderEntry,
Resource res) {
- assertEquals(resProviderEntry.getResourceProvider(),
- res.getResourceResolver());
+ ResourceProvider[] resourceProviders = resProviderEntry.getResourceProviders();
+ for ( ResourceProvider rp : resourceProviders ) {
+ if ( rp.equals(res.getResourceResolver())) {
+ return;
+ }
+ }
+ fail();
}
// The test provider implements the ResourceResolver interface and sets
@@ -237,6 +252,16 @@
public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
return null;
}
+
+ /**
+ * {@inheritDoc}
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return Arrays.toString(roots);
+ }
+
}
private static class TestResource implements Resource {