Author: cziegeler Date: Thu Apr 8 07:25:02 2010 New Revision: 931805 URL: http://svn.apache.org/viewvc?rev=931805&view=rev Log: SLING-585 : New functionality to resolve scripts by name
Added: sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/AbstractResourceCollector.java (with props) sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/NamedScriptResourceCollector.java (with props) Modified: sling/trunk/bundles/api/src/main/java/org/apache/sling/api/servlets/ServletResolver.java sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/SlingServletResolver.java sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/ResourceCollector.java sling/trunk/bundles/servlets/resolver/src/test/java/org/apache/sling/servlets/resolver/internal/helper/LocationIteratorTest.java Modified: sling/trunk/bundles/api/src/main/java/org/apache/sling/api/servlets/ServletResolver.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/src/main/java/org/apache/sling/api/servlets/ServletResolver.java?rev=931805&r1=931804&r2=931805&view=diff ============================================================================== --- sling/trunk/bundles/api/src/main/java/org/apache/sling/api/servlets/ServletResolver.java (original) +++ sling/trunk/bundles/api/src/main/java/org/apache/sling/api/servlets/ServletResolver.java Thu Apr 8 07:25:02 2010 @@ -21,6 +21,8 @@ package org.apache.sling.api.servlets; import javax.servlet.Servlet; import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; /** * The <code>ServletResolver</code> defines the API for a service capable of @@ -47,7 +49,7 @@ public interface ServletResolver { * implementing the {...@link OptingServlet} interface and returning * <code>false</code> when the * {...@link OptingServlet#accepts(SlingHttpServletRequest)} method is called. - * + * * @param request The {...@link SlingHttpServletRequest} object used to drive * selection of the servlet. * @return The servlet whose <code>service</code> method may be called to @@ -59,4 +61,59 @@ public interface ServletResolver { */ Servlet resolveServlet(SlingHttpServletRequest request); + /** + * Resolves a <code>javax.servlet.Servlet</code> whose + * <code>service</code> method may be used to handle a request. + * <p> + * The returned servlet must be assumed to be initialized and ready to run. + * That is, the <code>init</code> nor the <code>destroy</code> methods + * must <em>NOT</em> be called on the returned servlet. + * <p> + * This method skips all {...@link OptingServlet}s as there is no + * request object available. + * + * Basically this method searches a script with the <code>scriptName</code> + * for the resource type defined by the <code>resource</code> + * @param resource The {...@link Resource} object used to drive + * selection of the servlet. + * @param scriptName The name of the script - the script might have an + * extension. In this case only a script with the + * matching extension is used. + * @return The servlet whose <code>service</code> method may be called to + * handle the request. + * @throws org.apache.sling.api.SlingException Is thrown if an error occurrs + * while trying to find an appropriate servlet to handle the + * request or if no servlet could be resolved to handle the + * request. + * @since 2.1 + */ + Servlet resolveServlet(Resource resource, String scriptName); + + /** + * Resolves a <code>javax.servlet.Servlet</code> whose + * <code>service</code> method may be used to handle a request. + * <p> + * The returned servlet must be assumed to be initialized and ready to run. + * That is, the <code>init</code> nor the <code>destroy</code> methods + * must <em>NOT</em> be called on the returned servlet. + * <p> + * This method skips all {...@link OptingServlet}s as there is no + * request object available. + * + * Basically this method searches a script with the <code>scriptName</code> + * @param resolver The {...@link ResourceResolver} object used to drive + * selection of the servlet. + * @param scriptName The name of the script - the script might have an + * extension. In this case only a script with the + * matching extension is used. + * @return The servlet whose <code>service</code> method may be called to + * handle the request. + * @throws org.apache.sling.api.SlingException Is thrown if an error occurrs + * while trying to find an appropriate servlet to handle the + * request or if no servlet could be resolved to handle the + * request. + * @since 2.1 + */ + Servlet resolveServlet(ResourceResolver resolver, String scriptName); + } Modified: sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/SlingServletResolver.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/SlingServletResolver.java?rev=931805&r1=931804&r2=931805&view=diff ============================================================================== --- sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/SlingServletResolver.java (original) +++ sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/SlingServletResolver.java Thu Apr 8 07:25:02 2010 @@ -68,6 +68,8 @@ import org.apache.sling.jcr.api.SlingRep import org.apache.sling.jcr.resource.JcrResourceResolverFactory; import org.apache.sling.servlets.resolver.internal.defaults.DefaultErrorHandlerServlet; import org.apache.sling.servlets.resolver.internal.defaults.DefaultServlet; +import org.apache.sling.servlets.resolver.internal.helper.AbstractResourceCollector; +import org.apache.sling.servlets.resolver.internal.helper.NamedScriptResourceCollector; import org.apache.sling.servlets.resolver.internal.helper.ResourceCollector; import org.apache.sling.servlets.resolver.internal.helper.SlingServletConfig; import org.apache.sling.servlets.resolver.internal.resource.ServletResourceProvider; @@ -187,7 +189,7 @@ public class SlingServletResolver implem // a request. This field is set on demand by getDefaultErrorServlet() private Servlet fallbackErrorServlet; - private Map<ResourceCollector, Servlet> cache; + private Map<AbstractResourceCollector, Servlet> cache; private ServiceRegistration eventHandlerReg; @@ -263,7 +265,7 @@ public class SlingServletResolver implem // log the servlet found if (log.isDebugEnabled()) { if (servlet != null) { - log.info("Servlet {} found for resource={}", RequestUtil.getServletName(servlet), resource); + log.debug("Servlet {} found for resource={}", RequestUtil.getServletName(servlet), resource); } else { log.debug("No servlet found for resource={}", resource); } @@ -272,6 +274,86 @@ public class SlingServletResolver implem return servlet; } + /** + * @see org.apache.sling.api.servlets.ServletResolver#resolveServlet(org.apache.sling.api.resource.Resource, java.lang.String) + */ + public Servlet resolveServlet(final Resource resource, final String scriptName) { + if ( resource == null ) { + throw new IllegalArgumentException("Resource must not be null"); + } + if (log.isDebugEnabled()) { + log.debug("resolveServlet called for resource {} with script name {}", resource, scriptName); + } + + final Servlet servlet = resolveServlet(defaultScriptResolver, resource, scriptName); + + // log the servlet found + if (log.isDebugEnabled()) { + if (servlet != null) { + log.debug("Servlet {} found for resource {} and script name {}", new Object[] {RequestUtil.getServletName(servlet), resource, scriptName}); + } else { + log.debug("No servlet found for resource {} and script name {}", resource, scriptName); + } + } + + return servlet; + } + + /** + * @see org.apache.sling.api.servlets.ServletResolver#resolveServlet(org.apache.sling.api.resource.ResourceResolver, java.lang.String) + */ + public Servlet resolveServlet(final ResourceResolver resolver, final String scriptName) { + if ( resolver == null ) { + throw new IllegalArgumentException("Resource resolver must not be null"); + } + if (log.isDebugEnabled()) { + log.debug("resolveServlet called for for script name {}", scriptName); + } + + final Servlet servlet = resolveServlet(defaultScriptResolver, null, scriptName); + + // log the servlet found + if (log.isDebugEnabled()) { + if (servlet != null) { + log.debug("Servlet {} found for script name {}", RequestUtil.getServletName(servlet), scriptName); + } else { + log.debug("No servlet found for script name {}", scriptName); + } + } + + return servlet; + } + + private Servlet resolveServlet(final ResourceResolver resolver, + final Resource resource, + final String scriptName) { + Servlet servlet = null; + + // first check whether the type of a resource is the absolute + // path of a servlet (or script) + if (scriptName.charAt(0) == '/') { + final Resource res = resolver.getResource(scriptName); + if (res != null) { + servlet = res.adaptTo(Servlet.class); + } + if (servlet != null && log.isDebugEnabled()) { + log.debug("Servlet {} found using absolute resource type {}", RequestUtil.getServletName(servlet), + scriptName); + } + } + + // the resource type is not absolute, so lets go for the deep search + if (servlet == null) { + final NamedScriptResourceCollector locationUtil = NamedScriptResourceCollector.create(scriptName, resource); + servlet = getServlet(locationUtil, null, resolver); + + if (log.isDebugEnabled()) { + log.debug("resolveServlet returns servlet {}", RequestUtil.getServletName(servlet)); + } + } + return servlet; + + } // ---------- ScriptResolver interface ------------------------------------ public SlingScript findScript(ResourceResolver resourceResolver, String name) throws SlingException { @@ -501,7 +583,8 @@ public class SlingServletResolver implem * @return a servlet for handling the request or <code>null</code> if no * such servlet willing to handle the request could be found. */ - private Servlet getServlet(final ResourceCollector locationUtil, final SlingHttpServletRequest request, + private Servlet getServlet(final AbstractResourceCollector locationUtil, + final SlingHttpServletRequest request, final ResourceResolver scriptResolver) { final Servlet scriptServlet = (this.cache != null ? this.cache.get(locationUtil) : null); if (scriptServlet != null) { @@ -531,7 +614,7 @@ public class SlingServletResolver implem Servlet candidate = candidateResource.adaptTo(Servlet.class); if (candidate != null) { final boolean isOptingServlet = candidate instanceof OptingServlet; - boolean servletAcceptsRequest = !isOptingServlet || ((OptingServlet) candidate).accepts(request); + boolean servletAcceptsRequest = !isOptingServlet || (request != null && ((OptingServlet) candidate).accepts(request)); if (servletAcceptsRequest) { if (!hasOptingServlet && !isOptingServlet && this.cache != null) { this.cache.put(locationUtil, candidate); @@ -749,7 +832,7 @@ public class SlingServletResolver implem // create cache - if a cache size is configured final int cacheSize = OsgiUtil.toInteger(properties.get(PROP_CACHE_SIZE), DEFAULT_CACHE_SIZE); if (cacheSize > 5) { - this.cache = new ConcurrentHashMap<ResourceCollector, Servlet>(cacheSize); + this.cache = new ConcurrentHashMap<AbstractResourceCollector, Servlet>(cacheSize); } createAllServlets(refs); Added: sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/AbstractResourceCollector.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/AbstractResourceCollector.java?rev=931805&view=auto ============================================================================== --- sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/AbstractResourceCollector.java (added) +++ sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/AbstractResourceCollector.java Thu Apr 8 07:25:02 2010 @@ -0,0 +1,173 @@ +/* + * 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.servlets.resolver.internal.helper; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.api.resource.SyntheticResource; + +/** + * The <code>ResourceCollector</code> class provides a single public method - + * {...@link #getServlets(ResourceResolver)} - which is used to find an ordered collection + * of <code>Resource</code> instances which may be used to find a servlet or + * script to handle a request to the given resource. + */ +public abstract class AbstractResourceCollector { + + // the most generic resource type to use. This may be null in which + // case the default servlet name will be used as the base name + protected final String baseResourceType; + + // the request extension or null if the request has no extension + protected final String extension; + + protected int hashCode; + + protected final String resourceType; + + protected final String resourceSuperType; + + public AbstractResourceCollector(final String baseResourceType, + final String resourceType, + final String resourceSuperType, + final String extension) { + this.baseResourceType = baseResourceType; + this.resourceType = resourceType; + this.resourceSuperType = resourceSuperType; + this.extension = extension; + } + + public final Collection<Resource> getServlets(ResourceResolver resolver) { + + final SortedSet<Resource> resources = new TreeSet<Resource>(); + final Iterator<String> locations = new LocationIterator(resourceType, resourceSuperType, + baseResourceType, resolver); + while (locations.hasNext()) { + final String location = locations.next(); + + // get the location resource, use a synthetic resource if there + // is no real location. There may still be children at this + // location + final String path; + if ( location.endsWith("/") ) { + path = location.substring(0, location.length() - 1); + } else { + path = location; + } + final Resource locationRes = getResource(resolver, path); + getWeightedResources(resources, locationRes); + } + + return resources; + } + + abstract protected void getWeightedResources(final Set<Resource> resources, + final Resource location); + + /** + * Creates a {...@link WeightedResource} and adds it to the set of resources. + * The number of resources already present in the set is used as the ordinal + * number for the newly created resource. + * + * @param resources The set of resource to which the + * {...@link WeightedResource} is added. + * @param resource The <code>Resource</code> on which the + * {...@link WeightedResource} is based. + * @param numSelectors The number of request selectors which are matched by + * the name of the resource. + * @param methodPrefixWeight The method/prefix weight assigned to the + * resource according to the resource name. + */ + protected final void addWeightedResource(final Set<Resource> resources, + final Resource resource, + final int numSelectors, + final int methodPrefixWeight) { + final WeightedResource lr = new WeightedResource(resources.size(), resource, + numSelectors, methodPrefixWeight); + resources.add(lr); + } + + /** + * Returns a resource for the given <code>path</code>. + * If no resource exists at the given path a + * <code>SyntheticResource</code> is returned. + * + * @param resolver The <code>ResourceResolver</code> used to access the + * resource. + * @param path The absolute path of the resource to return. + * @return The actual resource at the given <code>path</code> or a + * synthetic resource representing the path location. + */ + protected final Resource getResource(final ResourceResolver resolver, + String path) { + Resource res = resolver.getResource(path); + + if (res == null) { + if (!path.startsWith("/")) { + path = "/".concat(path); + } + + res = new SyntheticResource(resolver, path, "$synthetic$"); + } + + return res; + } + + @Override + public boolean equals(Object obj) { + if ( !(obj instanceof AbstractResourceCollector) ) { + return false; + } + if ( obj == this ) { + return true; + } + final AbstractResourceCollector o = (AbstractResourceCollector)obj; + if ( stringEquals(resourceType, o.resourceType) + && stringEquals(resourceSuperType, o.resourceSuperType) + && stringEquals(extension, o.extension) + && stringEquals(baseResourceType, o.baseResourceType)) { + return true; + } + return false; + } + + @Override + public int hashCode() { + return this.hashCode; + } + + /** + * Helper method to compare two strings which can possibly be <code>null</code> + */ + protected boolean stringEquals(final String s1, final String s2) { + if ( s1 == null && s2 == null ) { + return true; + } + if ( s1 == null || s2 == null ) { + return false; + } + return s1.equals(s2); + } +} Propchange: sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/AbstractResourceCollector.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/AbstractResourceCollector.java ------------------------------------------------------------------------------ svn:keywords = author date id revision rev url Propchange: sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/AbstractResourceCollector.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/NamedScriptResourceCollector.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/NamedScriptResourceCollector.java?rev=931805&view=auto ============================================================================== --- sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/NamedScriptResourceCollector.java (added) +++ sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/NamedScriptResourceCollector.java Thu Apr 8 07:25:02 2010 @@ -0,0 +1,143 @@ +/* + * 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.servlets.resolver.internal.helper; + +import java.util.Iterator; +import java.util.Set; + +import org.apache.sling.api.resource.Resource; +import org.apache.sling.api.resource.ResourceResolver; +import org.apache.sling.api.resource.ResourceUtil; +import org.apache.sling.servlets.resolver.internal.ServletResolverConstants; + +/** + * The <code>ResourceCollector</code> class provides a single public method - + * {...@link #getServlets(ResourceResolver)} - which is used to find an ordered collection + * of <code>Resource</code> instances which may be used to find a servlet or + * script to handle a request to the given resource. + */ +public class NamedScriptResourceCollector extends AbstractResourceCollector { + + private final String scriptName; + + public static NamedScriptResourceCollector create(final String name, final Resource resource) { + final String resourceType; + final String resourceSuperType; + final String baseResourceType; + final String extension; + final String scriptName; + if ( resource != null ) { + resourceType = resource.getResourceType(); + resourceSuperType = resource.getResourceSuperType(); + baseResourceType = ServletResolverConstants.DEFAULT_SERVLET_NAME; + } else { + resourceType = ""; + resourceSuperType = null; + baseResourceType = ""; + } + final int pos = name.indexOf('.'); + if ( pos == -1 ) { + extension = null; + scriptName = name; + } else { + extension = name.substring(pos); + scriptName = name.substring(0, pos); + } + return new NamedScriptResourceCollector(baseResourceType, + resourceType, + resourceSuperType, + scriptName, + extension); + } + + public NamedScriptResourceCollector(final String baseResourceType, + final String resourceType, + final String resourceSuperType, + final String scriptName, + final String extension) { + super(baseResourceType, resourceType, resourceSuperType, extension); + this.scriptName = scriptName; + // create the hash code once + final String key = baseResourceType + ':' + this.scriptName + ':' + + this.resourceType + ':' + (this.resourceSuperType == null ? "" : this.resourceSuperType) + + ':' + (this.extension == null ? "" : this.extension); + this.hashCode = key.hashCode(); + } + + protected void getWeightedResources(final Set<Resource> resources, + final Resource location) { + final ResourceResolver resolver = location.getResourceResolver(); + // if extension is set, we just check the exact script + if ( this.extension != null ) { + final String path = location.getPath() + '/' + this.scriptName + this.extension; + final Resource current = resolver.getResource(path); + if ( current != null ) { + this.addWeightedResource(resources, current, 0, WeightedResource.WEIGHT_EXTENSION); + } + } else { + // if the script name denotes a path we have to get the denoted resource + // first + final Resource current; + final String name; + final int pos = this.scriptName.lastIndexOf('/'); + if ( pos == -1 ) { + current = location; + name = this.scriptName; + } else { + current = getResource(resolver, location.getPath() + '/' + this.scriptName.substring(0, pos)); + name = this.scriptName.substring(pos + 1); + } + final Iterator<Resource> children = resolver.listChildren(current); + while (children.hasNext()) { + final Resource child = children.next(); + + String scriptName = ResourceUtil.getName(child); + final int lastDot = scriptName.lastIndexOf('.'); + if (lastDot < 0) { + // no extension in the name, this is not a script + continue; + } + + scriptName = scriptName.substring(0, lastDot); + + if ( scriptName.equals(name) ) { + this.addWeightedResource(resources, child, 0, WeightedResource.WEIGHT_PREFIX); + continue; + } + } + } + } + + @Override + public boolean equals(Object obj) { + if ( !(obj instanceof NamedScriptResourceCollector) ) { + return false; + } + if ( obj == this ) { + return true; + } + if ( super.equals(obj) ) { + final NamedScriptResourceCollector o = (NamedScriptResourceCollector)obj; + if ( stringEquals(scriptName, o.scriptName)) { + return true; + } + } + return false; + } +} Propchange: sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/NamedScriptResourceCollector.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/NamedScriptResourceCollector.java ------------------------------------------------------------------------------ svn:keywords = author date id revision rev url Propchange: sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/NamedScriptResourceCollector.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/ResourceCollector.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/ResourceCollector.java?rev=931805&r1=931804&r2=931805&view=diff ============================================================================== --- sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/ResourceCollector.java (original) +++ sling/trunk/bundles/servlets/resolver/src/main/java/org/apache/sling/servlets/resolver/internal/helper/ResourceCollector.java Thu Apr 8 07:25:02 2010 @@ -18,18 +18,14 @@ */ package org.apache.sling.servlets.resolver.internal.helper; -import java.util.Collection; import java.util.Iterator; import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.request.RequestPathInfo; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.api.resource.ResourceUtil; -import org.apache.sling.api.resource.SyntheticResource; import org.apache.sling.servlets.resolver.internal.ServletResolverConstants; import org.apache.sling.servlets.resolver.internal.resource.ServletResourceProviderFactory; @@ -39,7 +35,7 @@ import org.apache.sling.servlets.resolve * of <code>Resource</code> instances which may be used to find a servlet or * script to handle a request to the given resource. */ -public class ResourceCollector { +public class ResourceCollector extends AbstractResourceCollector { /** * The special value returned by @@ -53,10 +49,6 @@ public class ResourceCollector { // the request method name used to indicate the script name private final String methodName; - // the most generic resource type to use. This may be null in which - // case the default servlet name will be used as the base name - private final String baseResourceType; - // the request selectors as a string converted to a realtive path or // null if the request has no selectors private final String[] requestSelectors; @@ -64,21 +56,12 @@ public class ResourceCollector { // the number of request selectors of the request or 0 if none private final int numRequestSelectors; - // the request extension or null if the request has no extension - private final String extension; - // request is GET or HEAD private final boolean isGet; // request is GET or HEAD and extension is html private final boolean isHtml; - private final int hashCode; - - private final String resourceType; - - private final String resourceSuperType; - private final String workspaceName; /** @@ -113,15 +96,15 @@ public class ResourceCollector { * @param resource the resource to invoke, the resource type and resource super type are taken from this resource. */ public ResourceCollector(String methodName, String baseResourceType, Resource resource, String workspaceName) { + super((baseResourceType != null ? baseResourceType : ServletResolverConstants.DEFAULT_SERVLET_NAME), + resource.getResourceType(), + resource.getResourceSuperType(), + null); this.methodName = methodName; - this.baseResourceType = (baseResourceType != null ? baseResourceType : ServletResolverConstants.DEFAULT_SERVLET_NAME); this.requestSelectors = new String[0]; this.numRequestSelectors = 0; - this.extension = null; this.isGet = false; this.isHtml = false; - this.resourceType = resource.getResourceType(); - this.resourceSuperType = resource.getResourceSuperType(); this.workspaceName = workspaceName; // create the hash code once @@ -145,16 +128,16 @@ public class ResourceCollector { * is assumed. */ private ResourceCollector(SlingHttpServletRequest request, String workspaceName) { + super(ServletResolverConstants.DEFAULT_SERVLET_NAME, + request.getResource().getResourceType(), + request.getResource().getResourceSuperType(), + request.getRequestPathInfo().getExtension()); this.methodName = request.getMethod(); - this.baseResourceType = ServletResolverConstants.DEFAULT_SERVLET_NAME; - this.resourceType = request.getResource().getResourceType(); - this.resourceSuperType = request.getResource().getResourceSuperType(); RequestPathInfo requestpaInfo = request.getRequestPathInfo(); requestSelectors = requestpaInfo.getSelectors(); numRequestSelectors = requestSelectors.length; - extension = request.getRequestPathInfo().getExtension(); isGet = "GET".equals(methodName) || "HEAD".equals(methodName); isHtml = isGet && "html".equals(extension); @@ -167,27 +150,8 @@ public class ResourceCollector { this.hashCode = key.hashCode(); } - public final Collection<Resource> getServlets(ResourceResolver resolver) { - - SortedSet<Resource> resources = new TreeSet<Resource>(); - - Iterator<String> locations = new LocationIterator(resourceType, resourceSuperType, - baseResourceType, resolver); - while (locations.hasNext()) { - String location = locations.next(); - - // get the location resource, use a synthetic resource if there - // is no real location. There may still be children at this - // location - Resource locationRes = getResource(resolver, location); - getWeightedResources(resources, locationRes); - } - - return resources; - } - - protected void getWeightedResources(Set<Resource> resources, - Resource location) { + protected void getWeightedResources(final Set<Resource> resources, + Resource location) { ResourceResolver resolver = location.getResourceResolver(); Resource current = location; @@ -281,53 +245,6 @@ public class ResourceCollector { } } - /** - * Creates a {...@link WeightedResource} and adds it to the set of resources. - * The number of resources already present in the set is used as the ordinal - * number for the newly created resource. - * - * @param resources The set of resource to which the - * {...@link WeightedResource} is added. - * @param resource The <code>Resource</code> on which the - * {...@link WeightedResource} is based. - * @param numSelectors The number of request selectors which are matched by - * the name of the resource. - * @param methodPrefixWeight The method/prefix weight assigned to the - * resource according to the resource name. - */ - protected final void addWeightedResource(Set<Resource> resources, - Resource resource, int numSelectors, int methodPrefixWeight) { - WeightedResource lr = new WeightedResource(resources.size(), resource, - numSelectors, methodPrefixWeight); - resources.add(lr); - } - - /** - * Returns a resource for the given <code>path</code>. - * If no resource exists at the given path a - * <code>SyntheticResource</code> is returned. - * - * @param resolver The <code>ResourceResolver</code> used to access the - * resource. - * @param path The absolute path of the resource to return. - * @return The actual resource at the given <code>path</code> or a - * synthetic resource representing the path location. - */ - protected final Resource getResource(ResourceResolver resolver, - String path) { - Resource res = resolver.getResource(path); - - if (res == null) { - if (!path.startsWith("/")) { - path = "/".concat(path); - } - - res = new SyntheticResource(resolver, path, "$synthetic$"); - } - - return res; - } - @Override public boolean equals(Object obj) { if ( !(obj instanceof ResourceCollector) ) { @@ -336,42 +253,22 @@ public class ResourceCollector { if ( obj == this ) { return true; } - final ResourceCollector o = (ResourceCollector)obj; - if ( isGet == o.isGet - && isHtml == o.isHtml - && numRequestSelectors == o.numRequestSelectors - && stringEquals(resourceType, o.resourceType) - && stringEquals(resourceSuperType, o.resourceSuperType) - && stringEquals(extension, o.extension) - && stringEquals(baseResourceType, o.baseResourceType) - && stringEquals(methodName, o.methodName) - && stringEquals(workspaceName, o.workspaceName)) { - // now compare selectors - for(int i=0;i<numRequestSelectors;i++) { - if ( !stringEquals(requestSelectors[i], o.requestSelectors[i]) ) { - return false; + if ( super.equals(obj) ) { + final ResourceCollector o = (ResourceCollector)obj; + if ( isGet == o.isGet + && isHtml == o.isHtml + && numRequestSelectors == o.numRequestSelectors + && stringEquals(methodName, o.methodName) + && stringEquals(workspaceName, o.workspaceName)) { + // now compare selectors + for(int i=0;i<numRequestSelectors;i++) { + if ( !stringEquals(requestSelectors[i], o.requestSelectors[i]) ) { + return false; + } } + return true; } - return true; } return false; } - - @Override - public int hashCode() { - return this.hashCode; - } - - /** - * Helper method to compare two strings which can possibly be <code>null</code> - */ - private boolean stringEquals(final String s1, final String s2) { - if ( s1 == null && s2 == null ) { - return true; - } - if ( s1 == null || s2 == null ) { - return false; - } - return s1.equals(s2); - } } Modified: sling/trunk/bundles/servlets/resolver/src/test/java/org/apache/sling/servlets/resolver/internal/helper/LocationIteratorTest.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/servlets/resolver/src/test/java/org/apache/sling/servlets/resolver/internal/helper/LocationIteratorTest.java?rev=931805&r1=931804&r2=931805&view=diff ============================================================================== --- sling/trunk/bundles/servlets/resolver/src/test/java/org/apache/sling/servlets/resolver/internal/helper/LocationIteratorTest.java (original) +++ sling/trunk/bundles/servlets/resolver/src/test/java/org/apache/sling/servlets/resolver/internal/helper/LocationIteratorTest.java Thu Apr 8 07:25:02 2010 @@ -408,4 +408,61 @@ public class LocationIteratorTest extend // 6. finished assertFalse(li.hasNext()); } + + public void testScriptNameWithoutResourceType() { + String root0 = "/apps"; + String root1 = "/libs"; + resourceResolver.setSearchPath(root0, root1); + LocationIterator li = new LocationIterator("", + null, + "", + resourceResolver); + assertTrue(li.hasNext()); + assertEquals("/apps/", li.next()); + assertTrue(li.hasNext()); + assertEquals("/libs/", li.next()); + assertFalse(li.hasNext()); + } + + public void testScriptNameWithResourceType() { + String root0 = "/apps"; + String root1 = "/libs"; + resourceResolver.setSearchPath(root0, root1); + LocationIterator li = new LocationIterator("a/b", + null, + DEFAULT_SERVLET_NAME, + resourceResolver); + assertTrue(li.hasNext()); + assertEquals(root0 + "/a/b", li.next()); + assertTrue(li.hasNext()); + assertEquals(root1 + "/a/b", li.next()); + assertTrue(li.hasNext()); + assertEquals(root0 + "/" + DEFAULT_SERVLET_NAME, li.next()); + assertTrue(li.hasNext()); + assertEquals(root1 + "/" + DEFAULT_SERVLET_NAME, li.next()); + assertFalse(li.hasNext()); + } + + public void testScriptNameWithResourceTypeAndSuperType() { + String root0 = "/apps"; + String root1 = "/libs"; + resourceResolver.setSearchPath(root0, root1); + LocationIterator li = new LocationIterator("a/b", + "c/d", + DEFAULT_SERVLET_NAME, + resourceResolver); + assertTrue(li.hasNext()); + assertEquals(root0 + "/a/b", li.next()); + assertTrue(li.hasNext()); + assertEquals(root1 + "/a/b", li.next()); + assertTrue(li.hasNext()); + assertEquals(root0 + "/c/d", li.next()); + assertTrue(li.hasNext()); + assertEquals(root1 + "/c/d", li.next()); + assertTrue(li.hasNext()); + assertEquals(root0 + "/" + DEFAULT_SERVLET_NAME, li.next()); + assertTrue(li.hasNext()); + assertEquals(root1 + "/" + DEFAULT_SERVLET_NAME, li.next()); + assertFalse(li.hasNext()); + } }