Return-Path: Delivered-To: apmail-incubator-sling-commits-archive@locus.apache.org Received: (qmail 7948 invoked from network); 28 Nov 2008 12:15:56 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 28 Nov 2008 12:15:56 -0000 Received: (qmail 60477 invoked by uid 500); 28 Nov 2008 12:16:07 -0000 Delivered-To: apmail-incubator-sling-commits-archive@incubator.apache.org Received: (qmail 60444 invoked by uid 500); 28 Nov 2008 12:16:07 -0000 Mailing-List: contact sling-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: sling-dev@incubator.apache.org Delivered-To: mailing list sling-commits@incubator.apache.org Received: (qmail 60434 invoked by uid 99); 28 Nov 2008 12:16:07 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 28 Nov 2008 04:16:07 -0800 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 28 Nov 2008 12:14:37 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id C4A002388892; Fri, 28 Nov 2008 04:14:53 -0800 (PST) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r721447 - in /incubator/sling/trunk/jcr/resource: ./ src/main/java/org/apache/sling/jcr/resource/internal/ src/main/java/org/apache/sling/jcr/resource/internal/helper/ src/main/resources/SLING-INF/nodetypes/ src/test/java/org/apache/sling/j... Date: Fri, 28 Nov 2008 12:14:53 -0000 To: sling-commits@incubator.apache.org From: fmeschbe@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20081128121453.C4A002388892@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: fmeschbe Date: Fri Nov 28 04:14:52 2008 New Revision: 721447 URL: http://svn.apache.org/viewvc?rev=721447&view=rev Log: SLING-249 Add support for old Virtual URLs and URL Mappings, add support for multiple internal redirect options, add support for setting the external redirect status, add namespace mangling Modified: incubator/sling/trunk/jcr/resource/pom.xml incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2.java incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/MapEntry.java incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/Mapping.java incubator/sling/trunk/jcr/resource/src/main/resources/SLING-INF/nodetypes/mapping.cnd incubator/sling/trunk/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2Test.java Modified: incubator/sling/trunk/jcr/resource/pom.xml URL: http://svn.apache.org/viewvc/incubator/sling/trunk/jcr/resource/pom.xml?rev=721447&r1=721446&r2=721447&view=diff ============================================================================== --- incubator/sling/trunk/jcr/resource/pom.xml (original) +++ incubator/sling/trunk/jcr/resource/pom.xml Fri Nov 28 04:14:52 2008 @@ -67,9 +67,9 @@ SLING-INF/nodetypes/folder.cnd, - SLING-INF/nodetypes/mapping.cnd, SLING-INF/nodetypes/resource.cnd, - SLING-INF/nodetypes/vanitypath.cnd + SLING-INF/nodetypes/vanitypath.cnd, + SLING-INF/nodetypes/mapping.cnd Modified: incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2.java URL: http://svn.apache.org/viewvc/incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2.java?rev=721447&r1=721446&r2=721447&view=diff ============================================================================== --- incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2.java (original) +++ incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2.java Fri Nov 28 04:14:52 2008 @@ -21,11 +21,17 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.StringTokenizer; +import java.util.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.jcr.RepositoryException; import javax.jcr.Session; @@ -34,6 +40,7 @@ import javax.jcr.query.QueryResult; import javax.jcr.query.RowIterator; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import org.apache.sling.adapter.SlingAdaptable; import org.apache.sling.api.SlingException; @@ -46,6 +53,7 @@ import org.apache.sling.api.resource.ValueMap; import org.apache.sling.jcr.resource.JcrResourceUtil; import org.apache.sling.jcr.resource.internal.helper.MapEntry; +import org.apache.sling.jcr.resource.internal.helper.Mapping; import org.apache.sling.jcr.resource.internal.helper.RedirectResource; import org.apache.sling.jcr.resource.internal.helper.ResourcePathIterator; import org.apache.sling.jcr.resource.internal.helper.jcr.JcrNodeResourceIterator; @@ -57,6 +65,20 @@ public class JcrResourceResolver2 extends SlingAdaptable implements ResourceResolver { + private static final String MANGLE_NAMESPACE_IN_SUFFIX = "_"; + + private static final String MANGLE_NAMESPACE_IN_PREFIX = "/_"; + + private static final String MANGLE_NAMESPACE_IN = "/_([^_]+)_"; + + private static final String MANGLE_NAMESPACE_OUT_SUFFIX = ":"; + + private static final String MANGLE_NAMESPACE_OUT_PREFIX = "/"; + + private static final String MANGLE_NAMESPACE_OUT = "/([^:]+):"; + + private static final String ANY_SCHEME_HOST = ".*/.*"; + private static final String MAP_ROOT = "/etc/map"; public static final String PROP_REG_EXP = "sling:match"; @@ -66,6 +88,8 @@ public static final String PROP_ALIAS = "sling:alias"; public static final String PROP_REDIRECT_EXTERNAL = "sling:redirect"; + + public static final String PROP_REDIRECT_EXTERNAL_STATUS = "sling:status"; /** default log */ private final Logger log = LoggerFactory.getLogger(getClass()); @@ -75,6 +99,8 @@ private final JcrResourceResolverFactoryImpl factory; private final List maps; + + private Set namespaces; public JcrResourceResolver2(JcrResourceProviderEntry rootProvider, JcrResourceResolverFactoryImpl factory) { @@ -93,8 +119,11 @@ absPath = "/"; } + // check for special namespace prefix treatment + absPath = unmangleNamespaces(absPath); + // Assume http://localhost:80 if request is null - String realPath = absPath; + String[] realPathList = { absPath }; String requestPath; if (request != null) { requestPath = getMapPath(request.getScheme(), @@ -111,7 +140,7 @@ // TODO: might do better to be able to log the loop and help the user for (int i = 0; i < 100; i++) { - String mappedPath = null; + String[] mappedPath = null; for (MapEntry mapEntry : maps) { mappedPath = mapEntry.replace(requestPath); if (mappedPath != null) { @@ -127,7 +156,7 @@ // external redirect log.debug("resolve: Returning external redirect"); - return new RedirectResource(this, absPath, mappedPath); + return new RedirectResource(this, absPath, mappedPath[0]); } } @@ -141,19 +170,19 @@ } // if the mapped path is not an URL, use this path to continue - if (!mappedPath.contains("://")) { + if (!mappedPath[0].contains("://")) { log.debug("resolve: Mapped path is for resource tree"); - realPath = mappedPath; + realPathList = mappedPath; break; } // otherwise the mapped path is an URI and we have to try to // resolve that URI now, using the URI's path as the real path try { - URI uri = new URI(mappedPath); + URI uri = new URI(mappedPath[0]); requestPath = getMapPath(uri.getScheme(), uri.getHost(), uri.getPort(), uri.getPath()); - realPath = uri.getPath(); + realPathList = new String[] { uri.getPath() }; log.debug( "resolve: Mapped path is an URL, using new request path {}", @@ -168,36 +197,43 @@ // this path may be absolute or relative, in which case we try // to resolve it against the search path - // first check whether the requested resource is a StarResource - if (StarResource.appliesTo(realPath)) { + Resource res = null; + for (int i = 0; res == null && i < realPathList.length; i++) { + String realPath = realPathList[i]; - log.debug("resolve: Mapped path {} is a Star Resource", realPath); - return new StarResource(this, ensureAbsPath(realPath), - factory.getJcrResourceTypeProvider()); - } + // first check whether the requested resource is a StarResource + if (StarResource.appliesTo(realPath)) { - Resource res = null; - if (realPath.startsWith("/")) { + log.debug("resolve: Mapped path {} is a Star Resource", + realPath); + res = new StarResource(this, ensureAbsPath(realPath), + factory.getJcrResourceTypeProvider()); - // let's check it with a direct access first - log.debug("resolve: Try absolute mapped path"); - res = resolveInternal(realPath); + } else - } else { + if (realPath.startsWith("/")) { + + // let's check it with a direct access first + log.debug("resolve: Try absolute mapped path"); + res = resolveInternal(realPath); + + } else { + + String[] searchPath = getSearchPath(); + for (int spi = 0; res == null && spi < searchPath.length; spi++) { + log.debug( + "resolve: Try relative mapped path with search path entry {}", + searchPath[spi]); + res = resolveInternal(searchPath[spi] + realPath); + } - String[] searchPath = getSearchPath(); - for (int i = 0; res == null && i < searchPath.length; i++) { - log.debug( - "resolve: Try relative mapped path with search path entry {}", - searchPath[i]); - res = resolveInternal(searchPath[i] + realPath); } } - + if (res == null) { - log.debug("resolve: Resource {} does not exist", realPath); - res = new NonExistingResource(this, ensureAbsPath(realPath)); + log.debug("resolve: Resource {} does not exist", realPathList[0]); + res = new NonExistingResource(this, ensureAbsPath(realPathList[0])); } else { log.debug("resolve: Found resource {}", res); } @@ -216,23 +252,30 @@ // trivial implementation not taking into account any mappings in // the content public String map(String resourcePath) { - return resourcePath; + return map(null, resourcePath); } // trivial implementation not taking into account any mappings in // the content and in /etc/map public String map(HttpServletRequest request, String resourcePath) { + StringBuilder sb = new StringBuilder(); - sb.append(request.getScheme()).append("://"); - sb.append(request.getServerName()); - if (request.getServerPort() > 0) { - sb.append(':').append(request.getServerPort()); - } - if (request.getContextPath() != null - && request.getContextPath().length() > 0) { - sb.append(request.getContextPath()); + + if (request != null) { + sb.append(request.getScheme()).append("://"); + sb.append(request.getServerName()); + if (request.getServerPort() > 0) { + sb.append(':').append(request.getServerPort()); + } + if (request.getContextPath() != null + && request.getContextPath().length() > 0) { + sb.append(request.getContextPath()); + } } - sb.append(resourcePath); + + // mangle the namespaces + sb.append(mangleNamespaces(resourcePath)); + return sb.toString(); } @@ -359,6 +402,23 @@ private Session getSession() { return rootProvider.getSession(); } + + private Set getNamespaces() { + if (namespaces == null) { + + // get the current set of namespaces, we cache throughout our + // life time.. + String[] namespaceList; + try { + namespaceList = getSession().getNamespacePrefixes(); + } catch (RepositoryException re) { + namespaceList = new String[0]; + } + + namespaces = new HashSet(Arrays.asList(namespaceList)); + } + return namespaces; + } /** * Returns a string used for matching map entries against the given request @@ -562,6 +622,9 @@ gather(entries, res, ""); } + // backwards-compatibility: read current configuration + gatherConfiguration(entries); + // backwards-compatible sling:vanityPath stuff gatherVanityPaths(entries); @@ -605,7 +668,7 @@ // what is stored in the sling:vanityPath property Object pVanityPath = row.get("sling:vanityPath"); if (pVanityPath != null) { - String url = ".*/.*" + String.valueOf(pVanityPath); + String url = ANY_SCHEME_HOST + String.valueOf(pVanityPath); // redirect target is the node providing the sling:vanityPath // property (or its parent if the node is called jcr:content) @@ -616,14 +679,86 @@ // whether the target is attained by a 302/FOUND or by an // internal redirect is defined by the sling:redirect property - boolean internal = true; - if (row.containsKey("sling:redirect")) { - internal = !Boolean.valueOf(String.valueOf(row.get("sling:redirect"))); + int status = -1; + if (row.containsKey("sling:redirect") + && Boolean.valueOf(String.valueOf(row.get("sling:redirect")))) { + status = HttpServletResponse.SC_FOUND; } - entries.add(new MapEntry(url, redirect, internal)); + entries.add(new MapEntry(url, redirect, status)); } } } + + private void gatherConfiguration(List entries) { + // virtual uris + Map virtuals = factory.getVirtualURLMap(); + if (virtuals != null) { + for (Entry virtualEntry : virtuals.entrySet()) { + String url = ANY_SCHEME_HOST + virtualEntry.getKey(); + String redirect = (String) virtualEntry.getValue(); + entries.add(new MapEntry(url, redirect, -1)); + } + } + + // URL Mappings + Mapping[] mappings = factory.getMappings(); + if (mappings != null) { + Map> map = new HashMap>(); + for (Mapping mapping : mappings) { + if (mapping.mapsInbound()) { + String url = mapping.getFrom(); + String alias = mapping.getTo(); + if (url.length() > 0) { + List aliasList = map.get(url); + if (aliasList == null) { + aliasList = new ArrayList(); + map.put(url, aliasList); + } + aliasList.add(alias); + } + } + } + for (Entry> entry : map.entrySet()) { + entries.add(new MapEntry(ANY_SCHEME_HOST + entry.getKey(), + entry.getValue().toArray(new String[0]), -1)); + } + } + } + + private String mangleNamespaces(String absPath) { + if (factory.isMangleNamespacePrefixes() && absPath.contains(MANGLE_NAMESPACE_OUT_SUFFIX)) { + Pattern p = Pattern.compile(MANGLE_NAMESPACE_OUT); + Matcher m = p.matcher(absPath); + StringBuffer buf = new StringBuffer(); + while (m.find()) { + String replacement = MANGLE_NAMESPACE_IN_PREFIX + m.group(1) + MANGLE_NAMESPACE_IN_SUFFIX; + m.appendReplacement(buf, replacement); + } + m.appendTail(buf); + absPath = buf.toString(); + } + + return absPath; + } + private String unmangleNamespaces(String absPath) { + if (factory.isMangleNamespacePrefixes() && absPath.contains(MANGLE_NAMESPACE_IN_PREFIX)) { + Set namespaces = getNamespaces(); + Pattern p = Pattern.compile(MANGLE_NAMESPACE_IN); + Matcher m = p.matcher(absPath); + StringBuffer buf = new StringBuffer(); + while (m.find()) { + String namespace = m.group(1); + if (namespaces.contains(namespace)) { + String replacement = MANGLE_NAMESPACE_OUT_PREFIX + namespace + MANGLE_NAMESPACE_OUT_SUFFIX; + m.appendReplacement(buf, replacement); + } + } + m.appendTail(buf); + absPath = buf.toString(); + } + + return absPath; + } } Modified: incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java URL: http://svn.apache.org/viewvc/incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java?rev=721447&r1=721446&r2=721447&view=diff ============================================================================== --- incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java (original) +++ incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/JcrResourceResolverFactoryImpl.java Fri Nov 28 04:14:52 2008 @@ -56,7 +56,7 @@ * descriptors provided by bundles. *
  • Fires OSGi EventAdmin events on behalf of internal helper objects * - * + * * @scr.component immediate="true" label="%resource.resolver.name" * description="%resource.resolver.description" * @scr.property name="service.description" @@ -69,14 +69,14 @@ * @scr.reference name="JcrResourceTypeProvider" * interface="org.apache.sling.jcr.resource.JcrResourceTypeProvider" * cardinality="0..n" policy="dynamic" - */ -public class JcrResourceResolverFactoryImpl - implements JcrResourceResolverFactory { +public class JcrResourceResolverFactoryImpl implements + JcrResourceResolverFactory { public final static class ResourcePattern { public final Pattern pattern; - public final String replacement; + + public final String replacement; public ResourcePattern(final Pattern p, final String r) { this.pattern = p; @@ -104,7 +104,7 @@ * maven plugin and the sling management console cannot handle empty * multivalue properties at the moment. So we just add a dummy direct * mapping. - * + * * @scr.property values.1="/-/" */ private static final String PROP_VIRTUAL = "resource.resolver.virtual"; @@ -118,8 +118,9 @@ private static final String PROP_MAPPING = "resource.resolver.mapping"; /** - * These regexps are executing during the resource resolving phase - * before the mappings are applied. + * These regexps are executing during the resource resolving phase before + * the mappings are applied. + * * @scr.property values.1="/_([^/]+?)_|/$1:" */ private static final String PROP_REGEXPS = "resource.resolver.regexps"; @@ -127,21 +128,47 @@ /** * These regexps are executed during a map operation as the back conversion * of the {@link #PROP_REGEXPS} + * * @scr.property values.1="/([^/]+?):([^/]+)|/_$1_$2" */ private static final String PROP_MAPREGEXPS = "resource.resolver.mapregexps"; + /** + * Defines whether namespace prefixes of resource names inside the path + * (e.g. jcr: in /home/path/jcr:content) are + * mangled or not. + *

    + * Mangling means the any namespace prefix contained in the path is replaced + * as per the generic substitution pattern /([^:]+):/_$1_/ + * when calling the map method of the resource resolver. + * Likewise the resolve methods will unmangle such namespace + * prefixes according to the substituation pattern + * /_([^_]+)_/$1:/. + *

    + * This feature is provided since there may be systems out there in the wild + * which cannot cope with URLs containing colons, even though they are + * perfectly valid characters in the path part of URI references with a + * scheme. + *

    + * The default value of this property if no configuration is provided is + * false. + * + * @scr.property value="false" type="Boolean" + */ + private static final String PROP_MANGLE_NAMESPACES = "resource.resolver.manglenamespaces"; + /** default log */ private final Logger log = LoggerFactory.getLogger(getClass()); /** * The JCR Repository we access to resolve resources - * + * * @scr.reference */ private SlingRepository repository; - /** The (optional) resource type providers. + /** + * The (optional) resource type providers. */ protected final List jcrResourceTypeProviders = new ArrayList(); @@ -178,7 +205,7 @@ private String[] searchPath; private ResourceProviderEntry rootProviderEntry; - + /** * Temporary field to select which JcrResourceResolver implementation to * use. @@ -187,6 +214,9 @@ * @see #getResourceResolver(Session) */ private boolean useNewResourceResolver; + + // whether to mangle paths with namespaces or not + private boolean mangleNamespacePrefixes; public JcrResourceResolverFactoryImpl() { this.rootProviderEntry = new ResourceProviderEntry("/", null, null); @@ -205,18 +235,18 @@ if (useNewResourceResolver) { return new JcrResourceResolver2(sessionRoot, this); } - + return new JcrResourceResolver(sessionRoot, this); } protected JcrResourceTypeProvider[] getJcrResourceTypeProvider() { JcrResourceTypeProvider[] providers = null; - synchronized ( this.jcrResourceTypeProviders ) { - if ( this.jcrResourceTypeProviders.size() > 0 ) { + synchronized (this.jcrResourceTypeProviders) { + if (this.jcrResourceTypeProviders.size() > 0) { providers = new JcrResourceTypeProvider[this.jcrResourceTypeProviders.size()]; int index = 0; final Iterator i = this.jcrResourceTypeProviders.iterator(); - while ( i.hasNext() ) { + while (i.hasNext()) { providers[index] = i.next().provider; } } @@ -243,6 +273,10 @@ : null; } + BidiMap getVirtualURLMap() { + return virtualURLMap; + } + Mapping[] getMappings() { return mappings; } @@ -259,6 +293,10 @@ return backPatterns; } + boolean isMangleNamespacePrefixes() { + return mangleNamespacePrefixes; + + } /** * Getter for rootProviderEntry, making it easier to extend * JcrResourceResolverFactoryImpl. See patterns = new ArrayList(); - if ( patternList != null ) { - for(final String p : patternList) { + if (patternList != null) { + for (final String p : patternList) { int pos = p.lastIndexOf('|'); - if ( pos == -1 ) { + if (pos == -1) { log.error("Invalid regexp: {}", p); } else { final String replString = p.substring(pos + 1); @@ -368,8 +410,8 @@ } protected void processDelayedJcrResourceTypeProviders() { - synchronized ( this.jcrResourceTypeProviders ) { - for(ServiceReference reference : delayedJcrResourceTypeProviders ) { + synchronized (this.jcrResourceTypeProviders) { + for (ServiceReference reference : delayedJcrResourceTypeProviders) { this.addJcrResourceTypeProvider(reference); } delayedJcrResourceTypeProviders.clear(); @@ -377,32 +419,34 @@ } protected void addJcrResourceTypeProvider(final ServiceReference reference) { - final Long id = (Long)reference.getProperty(Constants.SERVICE_ID); + final Long id = (Long) reference.getProperty(Constants.SERVICE_ID); long ranking = -1; - if ( reference.getProperty(Constants.SERVICE_RANKING) != null ) { - ranking = (Long)reference.getProperty(Constants.SERVICE_RANKING); + if (reference.getProperty(Constants.SERVICE_RANKING) != null) { + ranking = (Long) reference.getProperty(Constants.SERVICE_RANKING); } this.jcrResourceTypeProviders.add(new JcrResourceTypeProviderEntry(id, - ranking, - (JcrResourceTypeProvider)this.componentContext.locateService("JcrResourceTypeProvider", reference))); - Collections.sort(this.jcrResourceTypeProviders, new Comparator() { - - public int compare(JcrResourceTypeProviderEntry o1, - JcrResourceTypeProviderEntry o2) { - if ( o1.ranking < o2.ranking ) { - return 1; - } else if ( o1.ranking > o2.ranking ) { - return -1; - } else { - if ( o1.serviceId < o2.serviceId ) { - return -1; - } else if ( o1.serviceId > o2.serviceId ) { + ranking, + (JcrResourceTypeProvider) this.componentContext.locateService( + "JcrResourceTypeProvider", reference))); + Collections.sort(this.jcrResourceTypeProviders, + new Comparator() { + + public int compare(JcrResourceTypeProviderEntry o1, + JcrResourceTypeProviderEntry o2) { + if (o1.ranking < o2.ranking) { return 1; + } else if (o1.ranking > o2.ranking) { + return -1; + } else { + if (o1.serviceId < o2.serviceId) { + return -1; + } else if (o1.serviceId > o2.serviceId) { + return 1; + } } + return 0; } - return 0; - } - }); + }); } @@ -460,7 +504,7 @@ } protected void bindJcrResourceTypeProvider(ServiceReference reference) { - synchronized ( this.jcrResourceTypeProviders ) { + synchronized (this.jcrResourceTypeProviders) { if (componentContext == null) { delayedJcrResourceTypeProviders.add(reference); } else { @@ -470,13 +514,13 @@ } protected void unbindJcrResourceTypeProvider(ServiceReference reference) { - synchronized ( this.jcrResourceTypeProviders ) { + synchronized (this.jcrResourceTypeProviders) { delayedJcrResourceTypeProviders.remove(reference); - final long id = (Long)reference.getProperty(Constants.SERVICE_ID); + final long id = (Long) reference.getProperty(Constants.SERVICE_ID); final Iterator i = this.jcrResourceTypeProviders.iterator(); - while ( i.hasNext() ) { + while (i.hasNext()) { final JcrResourceTypeProviderEntry current = i.next(); - if ( current.serviceId == id ) { + if (current.serviceId == id) { i.remove(); } } @@ -492,12 +536,13 @@ protected static final class JcrResourceTypeProviderEntry { final long serviceId; + final long ranking; + final JcrResourceTypeProvider provider; - public JcrResourceTypeProviderEntry(final long id, - final long ranking, - final JcrResourceTypeProvider p) { + public JcrResourceTypeProviderEntry(final long id, final long ranking, + final JcrResourceTypeProvider p) { this.serviceId = id; this.ranking = ranking; this.provider = p; Modified: incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/MapEntry.java URL: http://svn.apache.org/viewvc/incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/MapEntry.java?rev=721447&r1=721446&r2=721447&view=diff ============================================================================== --- incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/MapEntry.java (original) +++ incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/MapEntry.java Fri Nov 28 04:14:52 2008 @@ -35,9 +35,9 @@ private final Pattern urlPattern; - private final String redirect; + private final String[] redirect; - private final boolean isInternal; + private final int status; public static MapEntry create(String url, Resource resource) { ValueMap props = resource.adaptTo(ValueMap.class); @@ -45,23 +45,29 @@ String redirect = props.get( JcrResourceResolver2.PROP_REDIRECT_EXTERNAL, String.class); if (redirect != null) { - return new MapEntry(url, redirect, false); + int status = props.get( + JcrResourceResolver2.PROP_REDIRECT_EXTERNAL_STATUS, 302); + return new MapEntry(url, redirect, status); } - redirect = props.get( - JcrResourceResolver2.PROP_REDIRECT_INTERNAL, String.class); - if (redirect != null) { - return new MapEntry(url, redirect, true); + String[] internalRedirect = props.get( + JcrResourceResolver2.PROP_REDIRECT_INTERNAL, String[].class); + if (internalRedirect != null) { + return new MapEntry(url, internalRedirect, -1); } } return null; } - public MapEntry(String url, String redirect, boolean isInternal) { + public MapEntry(String url, String redirect, int status) { + this(url, new String[]{ redirect }, status); + } + + public MapEntry(String url, String[] redirect, int status) { this.urlPattern = Pattern.compile(url); this.redirect = redirect; - this.isInternal = isInternal; + this.status = status; } public Matcher getMatcher(String value) { @@ -69,23 +75,32 @@ } // Returns the replacement or null if the value does not match - public String replace(String value) { + public String[] replace(String value) { Matcher m = urlPattern.matcher(value); if (m.find()) { + String[] redirects = getRedirect(); + String[] results = new String[redirects.length]; StringBuffer buf = new StringBuffer(); - m.appendReplacement(buf, getRedirect()); - m.appendTail(buf); - return buf.toString(); + for (int i=0; i < redirects.length; i++) { + m.appendReplacement(buf, redirects[i]); + m.appendTail(buf); + results[i] = buf.toString(); + } + return results; } return null; } - public String getRedirect() { + public String[] getRedirect() { return redirect; } public boolean isInternal() { - return isInternal; + return getStatus() < 0; + } + + public int getStatus() { + return status; } } Modified: incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/Mapping.java URL: http://svn.apache.org/viewvc/incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/Mapping.java?rev=721447&r1=721446&r2=721447&view=diff ============================================================================== --- incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/Mapping.java (original) +++ incubator/sling/trunk/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/Mapping.java Fri Nov 28 04:14:52 2008 @@ -165,6 +165,16 @@ + handle.substring(this.fromLength) : null; } + // TODO: temporary + public String getFrom() { + return from; + } + + // TODO: temporary + public String getTo() { + return to; + } + /** * Checks, if this mapping is defined for inbound mapping. * Modified: incubator/sling/trunk/jcr/resource/src/main/resources/SLING-INF/nodetypes/mapping.cnd URL: http://svn.apache.org/viewvc/incubator/sling/trunk/jcr/resource/src/main/resources/SLING-INF/nodetypes/mapping.cnd?rev=721447&r1=721446&r2=721447&view=diff ============================================================================== --- incubator/sling/trunk/jcr/resource/src/main/resources/SLING-INF/nodetypes/mapping.cnd (original) +++ incubator/sling/trunk/jcr/resource/src/main/resources/SLING-INF/nodetypes/mapping.cnd Fri Nov 28 04:14:52 2008 @@ -43,11 +43,15 @@ // segment, thus it should not contain any slashes - sling:match (string) - // Location header value for 302/FOUND response + // Location header value for response - sling:redirect (string) + // status code for redirect, defaults to 302 if not defined + - sling:status (long) + // internal redirect for further processing - sling:internalRedirect (string) + - sling:internalRedirect (string) multiple //----------------------------------------------------------------------------- Modified: incubator/sling/trunk/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2Test.java URL: http://svn.apache.org/viewvc/incubator/sling/trunk/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2Test.java?rev=721447&r1=721446&r2=721447&view=diff ============================================================================== --- incubator/sling/trunk/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2Test.java (original) +++ incubator/sling/trunk/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/JcrResourceResolver2Test.java Fri Nov 28 04:14:52 2008 @@ -66,13 +66,13 @@ "/SLING-INF/nodetypes/folder.cnd"))); assertTrue(RepositoryUtil.registerNodeType(getSession(), this.getClass().getResourceAsStream( - "/SLING-INF/nodetypes/mapping.cnd"))); - assertTrue(RepositoryUtil.registerNodeType(getSession(), - this.getClass().getResourceAsStream( "/SLING-INF/nodetypes/resource.cnd"))); assertTrue(RepositoryUtil.registerNodeType(getSession(), this.getClass().getResourceAsStream( "/SLING-INF/nodetypes/vanitypath.cnd"))); + assertTrue(RepositoryUtil.registerNodeType(getSession(), + this.getClass().getResourceAsStream( + "/SLING-INF/nodetypes/mapping.cnd"))); resFac = new JcrResourceResolverFactoryImpl();