You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by to...@apache.org on 2015/02/09 17:00:53 UTC
svn commit: r1658445 [1/2] - in /sling/trunk: ./
bundles/api/src/main/java/org/apache/sling/api/resource/
bundles/jcr/it-resource-versioning/ bundles/jcr/it-resource-versioning/src/
bundles/jcr/it-resource-versioning/src/test/ bundles/jcr/it-resource-v...
Author: tomekr
Date: Mon Feb 9 16:00:52 2015
New Revision: 1658445
URL: http://svn.apache.org/r1658445
Log:
SLING-848 Support getting versioned resources by using uri path parameters
Added:
sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ParametrizableResourceProvider.java
sling/trunk/bundles/jcr/it-resource-versioning/
sling/trunk/bundles/jcr/it-resource-versioning/.gitignore
sling/trunk/bundles/jcr/it-resource-versioning/pom.xml
sling/trunk/bundles/jcr/it-resource-versioning/src/
sling/trunk/bundles/jcr/it-resource-versioning/src/test/
sling/trunk/bundles/jcr/it-resource-versioning/src/test/java/
sling/trunk/bundles/jcr/it-resource-versioning/src/test/java/org/
sling/trunk/bundles/jcr/it-resource-versioning/src/test/java/org/apache/
sling/trunk/bundles/jcr/it-resource-versioning/src/test/java/org/apache/sling/
sling/trunk/bundles/jcr/it-resource-versioning/src/test/java/org/apache/sling/jcr/
sling/trunk/bundles/jcr/it-resource-versioning/src/test/java/org/apache/sling/jcr/resource/
sling/trunk/bundles/jcr/it-resource-versioning/src/test/java/org/apache/sling/jcr/resource/it/
sling/trunk/bundles/jcr/it-resource-versioning/src/test/java/org/apache/sling/jcr/resource/it/ResourceVersioningTest.java
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/params/
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/params/ParametersParser.java
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/params/ParsedParameters.java
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/params/PathParser.java
sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/tree/params/
sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/tree/params/PathParametersParserTest.java
Modified:
sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceMetadata.java
sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/package-info.java
sling/trunk/bundles/jcr/resource/pom.xml
sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrItemResource.java
sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResource.java
sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceIterator.java
sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResource.java
sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java
sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceTest.java
sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResourceTest.java
sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrTestNodeResource.java
sling/trunk/bundles/resourceresolver/pom.xml
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceIterator.java
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ProviderHandler.java
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderEntry.java
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderFactoryHandler.java
sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderHandler.java
sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/MockedResourceResolverImplTest.java
sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/ResourceResolverImplTest.java
sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/tree/ProviderHandlerTest.java
sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderEntryTest.java
sling/trunk/pom.xml
sling/trunk/testing/mocks/sling-mock/pom.xml
sling/trunk/testing/mocks/sling-mock/src/main/java/org/apache/sling/testing/mock/sling/MockJcrResourceResolverFactory.java
Added: sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ParametrizableResourceProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ParametrizableResourceProvider.java?rev=1658445&view=auto
==============================================================================
--- sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ParametrizableResourceProvider.java (added)
+++ sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ParametrizableResourceProvider.java Mon Feb 9 16:00:52 2015
@@ -0,0 +1,38 @@
+/*
+ * 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.api.resource;
+
+import java.util.Map;
+
+import aQute.bnd.annotation.ConsumerType;
+
+/**
+ * This extension allows resource provider implementations to support
+ * semicolon-separated parameters added to the URI, eg.: {@code /content/test;v='1.0'}.
+ *
+ * @since 2.8.0
+ */
+@ConsumerType
+public interface ParametrizableResourceProvider {
+
+ /**
+ * @see ResourceProvider#getResource(ResourceResolver, String)
+ */
+ Resource getResource(ResourceResolver resourceResolver, String path, Map<String, String> parameters);
+}
Modified: sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceMetadata.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceMetadata.java?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceMetadata.java (original)
+++ sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/ResourceMetadata.java Mon Feb 9 16:00:52 2015
@@ -21,6 +21,7 @@ package org.apache.sling.api.resource;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
@@ -126,6 +127,13 @@ public class ResourceMetadata extends Ha
*/
public static final String INTERNAL_CONTINUE_RESOLVING = ":org.apache.sling.resource.internal.continue.resolving";
+ /**
+ * Returns a map containing parameters added to path after semicolon.
+ * For instance, map for path <code>/content/test;v='1.2.3'.html</code>
+ * will contain one entry key <code>v</code> and value <code>1.2.3</code>.
+ */
+ public static final String PARAMETER_MAP = "sling.parameterMap";
+
private boolean isReadOnly = false;
/**
@@ -294,6 +302,32 @@ public class ResourceMetadata extends Ha
}
/**
+ * Sets the {@link #PARAMETER_MAP} property to
+ * <code>parameterMap</code> if not <code>null</code>.
+ */
+ public void setParameterMap(Map<String, String> parameterMap) {
+ if (parameterMap != null) {
+ put(PARAMETER_MAP, new LinkedHashMap<String, String>(parameterMap));
+ }
+ }
+
+ /**
+ * Returns the {@link #PARAMETER_MAP} property if not
+ * <code>null</code> and a <code>Map</code> instance. Otherwise
+ * <code>null</code> is returned.
+ */
+ @SuppressWarnings("unchecked")
+ public Map<String, String> getParameterMap() {
+ Object value = get(PARAMETER_MAP);
+ if (value instanceof Map) {
+ return (Map<String, String>) value;
+ }
+
+ return null;
+ }
+
+
+ /**
* Make this object read-only. All method calls trying to modify this object
* result in an exception!
* @since 2.3
Modified: sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/package-info.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/package-info.java?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/package-info.java (original)
+++ sling/trunk/bundles/api/src/main/java/org/apache/sling/api/resource/package-info.java Mon Feb 9 16:00:52 2015
@@ -17,7 +17,7 @@
* under the License.
*/
-@Version("2.7.0")
+@Version("2.8.0")
package org.apache.sling.api.resource;
import aQute.bnd.annotation.Version;
Added: sling/trunk/bundles/jcr/it-resource-versioning/.gitignore
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/it-resource-versioning/.gitignore?rev=1658445&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/it-resource-versioning/.gitignore (added)
+++ sling/trunk/bundles/jcr/it-resource-versioning/.gitignore Mon Feb 9 16:00:52 2015
@@ -0,0 +1,3 @@
+/jackrabbit
+/oak
+/sling
Added: sling/trunk/bundles/jcr/it-resource-versioning/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/it-resource-versioning/pom.xml?rev=1658445&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/it-resource-versioning/pom.xml (added)
+++ sling/trunk/bundles/jcr/it-resource-versioning/pom.xml Mon Feb 9 16:00:52 2015
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>sling</artifactId>
+ <version>22</version>
+ <relativePath>../../parent/pom.xml</relativePath>
+ </parent>
+
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.jcr.repository.it-resource-versioning</artifactId>
+ <packaging>jar</packaging>
+ <version>0.0.1-SNAPSHOT</version>
+
+ <name>Apache Sling Versioning Integration Tests</name>
+ <description>Tests versioning API implementation in JcrResourceProvider</description>
+ <inceptionYear>2015</inceptionYear>
+
+ <properties>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.testing.sling-mock</artifactId>
+ <version>1.1.3-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.testing.sling-mock-jackrabbit</artifactId>
+ <version>0.1.3-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.jcr</groupId>
+ <artifactId>jcr</artifactId>
+ <version>2.0</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
Added: sling/trunk/bundles/jcr/it-resource-versioning/src/test/java/org/apache/sling/jcr/resource/it/ResourceVersioningTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/it-resource-versioning/src/test/java/org/apache/sling/jcr/resource/it/ResourceVersioningTest.java?rev=1658445&view=auto
==============================================================================
--- sling/trunk/bundles/jcr/it-resource-versioning/src/test/java/org/apache/sling/jcr/resource/it/ResourceVersioningTest.java (added)
+++ sling/trunk/bundles/jcr/it-resource-versioning/src/test/java/org/apache/sling/jcr/resource/it/ResourceVersioningTest.java Mon Feb 9 16:00:52 2015
@@ -0,0 +1,160 @@
+/*
+ * 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.it;
+
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.version.VersionManager;
+import javax.naming.NamingException;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ValueMap;
+import org.apache.sling.testing.mock.sling.MockSling;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ResourceVersioningTest {
+
+ private VersionManager versionManager;
+
+ private Node testNode;
+
+ private ResourceResolver resolver;
+
+ private Session session;
+
+ @Before
+ public void setUp() throws Exception {
+ resolver = MockSling.newResourceResolver(ResourceResolverType.JCR_JACKRABBIT);
+ session = resolver.adaptTo(Session.class);
+ versionManager = session.getWorkspace().getVersionManager();
+ registerNamespace("sling", "http://sling.apache.org/jcr/sling/1.0");
+
+ Node testRoot = session.getRootNode().addNode("content");
+ testNode = testRoot.addNode("test");
+ testNode.addMixin(JcrConstants.MIX_VERSIONABLE);
+ session.save();
+
+ versionManager.checkout(testNode.getPath());
+ testNode.setProperty("prop", "oldvalue");
+ testNode.addNode("x").addNode("y").setProperty("child_prop", "child_old_value");
+ session.save();
+ versionManager.checkin(testNode.getPath());
+
+ versionManager.checkout(testNode.getPath());
+ testNode.setProperty("prop", "newvalue");
+ testNode.getProperty("x/y/child_prop").setValue("child_new_value");
+ session.save();
+ versionManager.checkin(testNode.getPath());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ session.removeItem("/content");
+ session.save();
+ resolver.close();
+ }
+
+ @Test
+ public void getResourceOnVersionableNode() throws RepositoryException, NamingException {
+ Resource resource = resolver.getResource("/content/test;v='1.0'");
+ String prop = resource.adaptTo(ValueMap.class).get("prop", String.class);
+ assertEquals("/content/test;v='1.0'", resource.getPath());
+ assertEquals("oldvalue", prop);
+ }
+
+ @Test
+ public void getResourceOnVersionableProperty() throws RepositoryException, NamingException {
+ Resource resource = resolver.getResource("/content/test/prop;v='1.0'");
+ String prop = resource.adaptTo(String.class);
+ assertEquals("/content/test/prop;v='1.0'", resource.getPath());
+ assertEquals("oldvalue", prop);
+ }
+
+ @Test
+ public void resolveOnVersionableNode() throws RepositoryException, NamingException {
+ for (String path : Arrays.asList("/content/test;v='1.0'.html", "/content/test.html;v=1.0",
+ "/content/test;v='1.0'.html/some/suffix", "/content/test.html;v=1.0/some/suffix")) {
+ Resource resource = resolver.resolve(path);
+ String prop = resource.adaptTo(ValueMap.class).get("prop", String.class);
+ assertEquals("/content/test;v='1.0'", resource.getPath());
+ assertEquals("oldvalue", prop);
+ }
+ }
+
+ @Test
+ public void getResourceOnVersionableDescendant() throws RepositoryException, NamingException {
+ Resource resource = resolver.getResource("/content/test/x/y;v='1.0'");
+ String prop = resource.adaptTo(ValueMap.class).get("child_prop", String.class);
+ assertEquals("/content/test/x/y;v='1.0'", resource.getPath());
+ assertEquals("child_old_value", prop);
+ }
+
+ @Test
+ public void getResourceOnVersionableDescendantProperty() throws RepositoryException, NamingException {
+ Resource resource = resolver.getResource("/content/test/x/y/child_prop;v='1.0'");
+ String prop = resource.adaptTo(String.class);
+ assertEquals("/content/test/x/y/child_prop;v='1.0'", resource.getPath());
+ assertEquals("child_old_value", prop);
+ }
+
+ @Test
+ public void getChildOnVersionableResource() throws RepositoryException, NamingException {
+ Resource resource = resolver.getResource("/content/test;v='1.0'").getChild("x/y");
+ String prop = resource.adaptTo(ValueMap.class).get("child_prop", String.class);
+ assertEquals("/content/test/x/y;v='1.0'", resource.getPath());
+ assertEquals("child_old_value", prop);
+ }
+
+ @Test
+ public void listChildrenOnVersionableResource() throws RepositoryException, NamingException {
+ Resource resource = resolver.getResource("/content/test/x;v='1.0'").listChildren().next();
+ String prop = resource.adaptTo(ValueMap.class).get("child_prop", String.class);
+ assertEquals("/content/test/x/y;v='1.0'", resource.getPath());
+ assertEquals("child_old_value", prop);
+ }
+
+ @Test
+ public void getParentOnVersionableResource() throws RepositoryException, NamingException {
+ Resource resource = resolver.getResource("/content/test/x;v='1.0'").getParent();
+ String prop = resource.adaptTo(ValueMap.class).get("prop", String.class);
+ assertEquals("/content/test", resource.getPath());
+ assertEquals("newvalue", prop);
+ }
+
+ private void registerNamespace(String prefix, String uri) throws RepositoryException {
+ NamespaceRegistry registry = session.getWorkspace().getNamespaceRegistry();
+ if (!ArrayUtils.contains(registry.getPrefixes(), prefix)) {
+ session.getWorkspace().getNamespaceRegistry().registerNamespace(prefix, uri);
+ }
+
+ }
+}
Modified: sling/trunk/bundles/jcr/resource/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/pom.xml?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/pom.xml (original)
+++ sling/trunk/bundles/jcr/resource/pom.xml Mon Feb 9 16:00:52 2015
@@ -142,7 +142,7 @@
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.api</artifactId>
- <version>2.8.0</version>
+ <version>2.8.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrItemResource.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrItemResource.java?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrItemResource.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrItemResource.java Mon Feb 9 16:00:52 2015
@@ -47,7 +47,9 @@ abstract class JcrItemResource<T extends
private final ResourceResolver resourceResolver;
- private String path;
+ protected final String path;
+
+ protected final String version;
private final T item;
@@ -57,12 +59,14 @@ abstract class JcrItemResource<T extends
protected JcrItemResource(final ResourceResolver resourceResolver,
final String path,
+ final String version,
final T item,
final ResourceMetadata metadata,
final PathMapper pathMapper) {
this.resourceResolver = resourceResolver;
this.path = path;
+ this.version = version;
this.item = item;
this.metadata = metadata;
this.pathMapper = pathMapper;
@@ -79,7 +83,13 @@ abstract class JcrItemResource<T extends
* @see org.apache.sling.api.resource.Resource#getPath()
*/
public String getPath() {
- return path;
+ if (version == null) {
+ return path;
+ } else if (version.contains(".")) {
+ return String.format("%s;v='%s'", path, version);
+ } else {
+ return String.format("%s;v=%s", path, version);
+ }
}
/**
Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResource.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResource.java?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResource.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResource.java Mon Feb 9 16:00:52 2015
@@ -77,10 +77,11 @@ class JcrNodeResource extends JcrItemRes
*/
public JcrNodeResource(final ResourceResolver resourceResolver,
final String path,
+ final String version,
final Node node,
final ClassLoader dynamicClassLoader,
final PathMapper pathMapper) {
- super(resourceResolver, path, node, new JcrNodeResourceMetadata(node), pathMapper);
+ super(resourceResolver, path, version, node, new JcrNodeResourceMetadata(node), pathMapper);
this.pathMapper = pathMapper;
this.dynamicClassLoader = dynamicClassLoader;
this.resourceSuperType = UNSET_RESOURCE_SUPER_TYPE;
@@ -241,7 +242,7 @@ class JcrNodeResource extends JcrItemRes
Iterator<Resource> listJcrChildren() {
try {
if (getNode().hasNodes()) {
- return new JcrNodeResourceIterator(getResourceResolver(),
+ return new JcrNodeResourceIterator(getResourceResolver(), path, version,
getNode().getNodes(), this.dynamicClassLoader, pathMapper);
}
} catch (final RepositoryException re) {
Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceIterator.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceIterator.java?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceIterator.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceIterator.java Mon Feb 9 16:00:52 2015
@@ -23,6 +23,7 @@ import java.util.NoSuchElementException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
@@ -53,6 +54,10 @@ public class JcrNodeResourceIterator imp
private final PathMapper pathMapper;
+ private final String parentPath;
+
+ private final String parentVersion;
+
/**
* Creates an instance using the given resource manager and the nodes
* provided as a node iterator.
@@ -61,7 +66,23 @@ public class JcrNodeResourceIterator imp
final NodeIterator nodes,
final ClassLoader dynamicClassLoader,
final PathMapper pathMapper) {
+ this(resourceResolver, null, null, nodes, dynamicClassLoader, pathMapper);
+ }
+
+ /**
+ * Creates an instance using the given resource manager and the nodes
+ * provided as a node iterator. Paths of the iterated resources will be
+ * concatenated from the parent path, node name and the version number.
+ */
+ public JcrNodeResourceIterator(final ResourceResolver resourceResolver,
+ final String parentPath,
+ final String parentVersion,
+ final NodeIterator nodes,
+ final ClassLoader dynamicClassLoader,
+ final PathMapper pathMapper) {
this.resourceResolver = resourceResolver;
+ this.parentPath = parentPath;
+ this.parentVersion = parentVersion;
this.nodes = nodes;
this.dynamicClassLoader = dynamicClassLoader;
this.pathMapper = pathMapper;
@@ -94,11 +115,10 @@ public class JcrNodeResourceIterator imp
while (nodes.hasNext()) {
try {
final Node n = nodes.nextNode();
- final String path = pathMapper.mapJCRPathToResourcePath(n.getPath());
+ final String path = getPath(n);
if ( path != null ) {
final Resource resource = new JcrNodeResource(resourceResolver,
- path,
- n, dynamicClassLoader, pathMapper);
+ path, parentVersion, n, dynamicClassLoader, pathMapper);
LOGGER.debug("seek: Returning Resource {}", resource);
return resource;
}
@@ -113,4 +133,14 @@ public class JcrNodeResourceIterator imp
LOGGER.debug("seek: No more nodes, iterator exhausted");
return null;
}
+
+ private String getPath(Node node) throws RepositoryException {
+ final String path;
+ if (parentPath == null) {
+ path = node.getPath();
+ } else {
+ path = String.format("%s/%s", parentPath, node.getName());
+ }
+ return pathMapper.mapJCRPathToResourcePath(path);
+ }
}
Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResource.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResource.java?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResource.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResource.java Mon Feb 9 16:00:52 2015
@@ -53,10 +53,11 @@ class JcrPropertyResource extends JcrIte
public JcrPropertyResource(final ResourceResolver resourceResolver,
final String path,
+ final String version,
final Property property,
final PathMapper pathMapper)
throws RepositoryException {
- super(resourceResolver, path, property, new ResourceMetadata(), pathMapper);
+ super(resourceResolver, path, version, property, new ResourceMetadata(), pathMapper);
this.resourceType = getResourceTypeForNode(property.getParent())
+ "/" + property.getName();
if (PropertyType.BINARY != getProperty().getType()) {
Modified: sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java (original)
+++ sling/trunk/bundles/jcr/resource/src/main/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrResourceProvider.java Mon Feb 9 16:00:52 2015
@@ -20,11 +20,14 @@ package org.apache.sling.jcr.resource.in
import java.security.Principal;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.Queue;
import java.util.Set;
import javax.jcr.Item;
@@ -37,8 +40,12 @@ import javax.jcr.query.Query;
import javax.jcr.query.QueryResult;
import javax.jcr.query.Row;
import javax.jcr.query.RowIterator;
+import javax.jcr.version.VersionHistory;
+import javax.jcr.version.VersionManager;
import javax.servlet.http.HttpServletRequest;
+import org.apache.commons.lang.StringUtils;
+import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.api.JackrabbitSession;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.UserManager;
@@ -47,6 +54,7 @@ import org.apache.sling.api.adapter.Slin
import org.apache.sling.api.resource.AttributableResourceProvider;
import org.apache.sling.api.resource.DynamicResourceProvider;
import org.apache.sling.api.resource.ModifyingResourceProvider;
+import org.apache.sling.api.resource.ParametrizableResourceProvider;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.QueriableResourceProvider;
import org.apache.sling.api.resource.QuerySyntaxException;
@@ -77,7 +85,8 @@ public class JcrResourceProvider
AttributableResourceProvider,
QueriableResourceProvider,
RefreshableResourceProvider,
- ModifyingResourceProvider {
+ ModifyingResourceProvider,
+ ParametrizableResourceProvider {
/** column name for node path */
private static final String QUERY_COLUMN_PATH = "jcr:path";
@@ -125,7 +134,7 @@ public class JcrResourceProvider
@SuppressWarnings("javadoc")
public Resource getResource(ResourceResolver resourceResolver,
HttpServletRequest request, String path) throws SlingException {
- return getResource(resourceResolver, path);
+ return getResource(resourceResolver, path, Collections.<String, String> emptyMap());
}
/**
@@ -133,9 +142,18 @@ public class JcrResourceProvider
*/
public Resource getResource(ResourceResolver resourceResolver, String path)
throws SlingException {
+ return getResource(resourceResolver, path, Collections.<String, String> emptyMap());
+ }
+
+
+ /**
+ * @see org.apache.sling.api.resource.ResourceProvider#getResource(org.apache.sling.api.resource.ResourceResolver, java.lang.String)
+ */
+ public Resource getResource(ResourceResolver resourceResolver, String path, Map<String, String> parameters)
+ throws SlingException {
this.checkClosed();
try {
- return createResource(resourceResolver, path);
+ return createResource(resourceResolver, path, parameters);
} catch (RepositoryException re) {
throw new SlingException("Problem retrieving node based resource "
+ path, re);
@@ -162,7 +180,7 @@ public class JcrResourceProvider
// children
try {
parentItemResource = createResource(
- parent.getResourceResolver(), parent.getPath());
+ parent.getResourceResolver(), parent.getPath(), Collections.<String, String> emptyMap());
} catch (RepositoryException re) {
parentItemResource = null;
}
@@ -189,28 +207,86 @@ public class JcrResourceProvider
* item in the repository.
*/
private JcrItemResource createResource(final ResourceResolver resourceResolver,
- final String resourcePath) throws RepositoryException {
+ final String resourcePath, final Map<String, String> parameters) throws RepositoryException {
final String jcrPath = pathMapper.mapResourcePathToJCRPath(resourcePath);
if (jcrPath != null && itemExists(jcrPath)) {
Item item = session.getItem(jcrPath);
+ final String version;
+ if (parameters != null && parameters.containsKey("v")) {
+ version = parameters.get("v");
+ item = getHistoricItem(item, version);
+ } else {
+ version = null;
+ }
if (item.isNode()) {
log.debug(
"createResource: Found JCR Node Resource at path '{}'",
resourcePath);
- return new JcrNodeResource(resourceResolver, resourcePath, (Node) item, dynamicClassLoader, pathMapper);
+ final JcrNodeResource resource = new JcrNodeResource(resourceResolver, resourcePath, version, (Node) item, dynamicClassLoader, pathMapper);
+ resource.getResourceMetadata().setParameterMap(parameters);
+ return resource;
}
log.debug(
"createResource: Found JCR Property Resource at path '{}'",
resourcePath);
- return new JcrPropertyResource(resourceResolver, resourcePath,
+ final JcrPropertyResource resource = new JcrPropertyResource(resourceResolver, resourcePath, version,
(Property) item, pathMapper);
+ resource.getResourceMetadata().setParameterMap(parameters);
+ return resource;
}
log.debug("createResource: No JCR Item exists at path '{}'", jcrPath);
return null;
}
+ private Item getHistoricItem(Item item, String versionSpecifier) throws RepositoryException {
+ Item currentItem = item;
+ LinkedList<String> relPath = new LinkedList<String>();
+ Node version = null;
+ while (!"/".equals(currentItem.getPath())) {
+ if (isVersionable(currentItem)) {
+ version = getFrozenNode((Node) currentItem, versionSpecifier);
+ break;
+ } else {
+ relPath.addFirst(currentItem.getName());
+ currentItem = currentItem.getParent();
+ }
+ }
+ if (version != null) {
+ return getSubitem(version, StringUtils.join(relPath.iterator(), '/'));
+ }
+ return null;
+ }
+
+ private static Item getSubitem(Node node, String relPath) throws RepositoryException {
+ if (relPath.length() == 0) { // not using isEmpty() due to 1.5 compatibility
+ return node;
+ } else if (node.hasNode(relPath)) {
+ return node.getNode(relPath);
+ } else if (node.hasProperty(relPath)) {
+ return node.getProperty(relPath);
+ } else {
+ return null;
+ }
+ }
+
+ private Node getFrozenNode(Node node, String versionSpecifier) throws RepositoryException {
+ final VersionManager versionManager = session.getWorkspace().getVersionManager();
+ final VersionHistory history = versionManager.getVersionHistory(node.getPath());
+ if (history.hasVersionLabel(versionSpecifier)) {
+ return history.getVersionByLabel(versionSpecifier).getFrozenNode();
+ } else if (history.hasNode(versionSpecifier)) {
+ return history.getVersion(versionSpecifier).getFrozenNode();
+ } else {
+ return null;
+ }
+ }
+
+ private static boolean isVersionable(Item item) throws RepositoryException {
+ return item.isNode() && ((Node) item).isNodeType(JcrConstants.MIX_VERSIONABLE);
+ }
+
/**
* Checks whether the item exists and this content manager's session has
* read access to the item. If the item does not exist, access control is
@@ -515,7 +591,7 @@ public class JcrResourceProvider
}
}
- return new JcrNodeResource(resolver, resourcePath, node, this.dynamicClassLoader, pathMapper);
+ return new JcrNodeResource(resolver, resourcePath, null, node, this.dynamicClassLoader, pathMapper);
} catch (final RepositoryException e) {
throw new PersistenceException("Unable to create node at " + jcrPath, e, resourcePath, null);
}
Modified: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceTest.java?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceTest.java (original)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrNodeResourceTest.java Mon Feb 9 16:00:52 2015
@@ -45,7 +45,7 @@ public class JcrNodeResourceTest extends
getSession().save();
file = rootNode.getNode(name);
- JcrNodeResource jnr = new JcrNodeResource(null, file.getPath(), file, null, new PathMapperImpl());
+ JcrNodeResource jnr = new JcrNodeResource(null, file.getPath(), null, file, null, new PathMapperImpl());
assertEquals(file.getPath(), jnr.getPath());
@@ -63,7 +63,7 @@ public class JcrNodeResourceTest extends
getSession().save();
file = rootNode.getNode(name);
- JcrNodeResource jnr = new JcrNodeResource(null, file.getPath(), file, null, new PathMapperImpl());
+ JcrNodeResource jnr = new JcrNodeResource(null, file.getPath(), null, file, null, new PathMapperImpl());
assertEquals(file.getPath(), jnr.getPath());
@@ -79,7 +79,7 @@ public class JcrNodeResourceTest extends
getSession().save();
res = rootNode.getNode(name);
- JcrNodeResource jnr = new JcrNodeResource(null, res.getPath(), res, null, new PathMapperImpl());
+ JcrNodeResource jnr = new JcrNodeResource(null, res.getPath(), null, res, null, new PathMapperImpl());
assertEquals(res.getPath(), jnr.getPath());
@@ -95,7 +95,7 @@ public class JcrNodeResourceTest extends
getSession().save();
res = rootNode.getNode(name);
- JcrNodeResource jnr = new JcrNodeResource(null, res.getPath(), res, null, new PathMapperImpl());
+ JcrNodeResource jnr = new JcrNodeResource(null, res.getPath(), null, res, null, new PathMapperImpl());
assertEquals(res.getPath(), jnr.getPath());
@@ -108,14 +108,14 @@ public class JcrNodeResourceTest extends
Node node = rootNode.addNode(name, JcrConstants.NT_UNSTRUCTURED);
getSession().save();
- JcrNodeResource jnr = new JcrNodeResource(null, node.getPath(), node, null, new PathMapperImpl());
+ JcrNodeResource jnr = new JcrNodeResource(null, node.getPath(), null, node, null, new PathMapperImpl());
assertEquals(JcrConstants.NT_UNSTRUCTURED, jnr.getResourceType());
String typeName = "some/resource/type";
node.setProperty(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY, typeName);
getSession().save();
- jnr = new JcrNodeResource(null, node.getPath(), node, null, new PathMapperImpl());
+ jnr = new JcrNodeResource(null, node.getPath(), null, node, null, new PathMapperImpl());
assertEquals(typeName, jnr.getResourceType());
}
@@ -127,7 +127,7 @@ public class JcrNodeResourceTest extends
node.setProperty(JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY, typeName);
getSession().save();
- Resource jnr = new JcrNodeResource(null, node.getPath(), node, null, new PathMapperImpl());
+ Resource jnr = new JcrNodeResource(null, node.getPath(), null, node, null, new PathMapperImpl());
assertEquals(typeName, jnr.getResourceType());
// default super type is null
@@ -138,7 +138,7 @@ public class JcrNodeResourceTest extends
typeNode.setProperty(JcrResourceConstants.SLING_RESOURCE_SUPER_TYPE_PROPERTY, superTypeName);
getSession().save();
- jnr = new JcrNodeResource(null, typeNode.getPath(), typeNode, null, new PathMapperImpl());
+ jnr = new JcrNodeResource(null, typeNode.getPath(), null, typeNode, null, new PathMapperImpl());
assertEquals(JcrConstants.NT_UNSTRUCTURED, jnr.getResourceType());
assertEquals(superTypeName, jnr.getResourceSuperType());
@@ -147,7 +147,7 @@ public class JcrNodeResourceTest extends
node.setProperty(JcrResourceConstants.SLING_RESOURCE_SUPER_TYPE_PROPERTY, otherSuperTypeName);
getSession().save();
- jnr = new JcrNodeResource(null, node.getPath(), node, null, new PathMapperImpl());
+ jnr = new JcrNodeResource(null, node.getPath(), null, node, null, new PathMapperImpl());
assertEquals(typeName, jnr.getResourceType());
assertEquals(otherSuperTypeName, jnr.getResourceSuperType());
@@ -155,7 +155,7 @@ public class JcrNodeResourceTest extends
node.getProperty(JcrResourceConstants.SLING_RESOURCE_SUPER_TYPE_PROPERTY).remove();
getSession().save();
- jnr = new JcrNodeResource(null, node.getPath(), node, null, new PathMapperImpl());
+ jnr = new JcrNodeResource(null, node.getPath(), null, node, null, new PathMapperImpl());
assertEquals(typeName, jnr.getResourceType());
assertNull(jnr.getResourceSuperType());
}
@@ -168,7 +168,7 @@ public class JcrNodeResourceTest extends
getSession().save();
res = rootNode.getNode(name);
- JcrNodeResource jnr = new JcrNodeResource(null, res.getPath(), res, null, new PathMapperImpl());
+ JcrNodeResource jnr = new JcrNodeResource(null, res.getPath(), null, res, null, new PathMapperImpl());
final Map<?, ?> props = jnr.adaptTo(Map.class);
@@ -235,7 +235,7 @@ public class JcrNodeResourceTest extends
getSession().save();
file = rootNode.getNode(name);
- JcrNodeResource jnr = new JcrNodeResource(null, file.getPath(), file, null, new PathMapperImpl());
+ JcrNodeResource jnr = new JcrNodeResource(null, file.getPath(), null, file, null, new PathMapperImpl());
assertEquals(utf8bytes, jnr.adaptTo(InputStream.class));
assertEquals(utf8bytes.length, jnr.getResourceMetadata().getContentLength());
Modified: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResourceTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResourceTest.java?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResourceTest.java (original)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrPropertyResourceTest.java Mon Feb 9 16:00:52 2015
@@ -73,7 +73,7 @@ public class JcrPropertyResourceTest {
allowing(property).getType(); will(returnValue(data.getValue()));
allowing(property).getString(); will(returnValue(stringValue));
}});
- final JcrPropertyResource propResource = new JcrPropertyResource(resolver, "/path/to/string-property", property, new PathMapperImpl());
+ final JcrPropertyResource propResource = new JcrPropertyResource(resolver, "/path/to/string-property", null, property, new PathMapperImpl());
assertEquals("Byte length of " + stringValue, stringByteLength, propResource.getResourceMetadata().getContentLength());
}
}
Modified: sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrTestNodeResource.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrTestNodeResource.java?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrTestNodeResource.java (original)
+++ sling/trunk/bundles/jcr/resource/src/test/java/org/apache/sling/jcr/resource/internal/helper/jcr/JcrTestNodeResource.java Mon Feb 9 16:00:52 2015
@@ -28,7 +28,7 @@ public class JcrTestNodeResource extends
public JcrTestNodeResource(ResourceResolver resourceResolver, Node node,
ClassLoader dynamicClassLoader) throws RepositoryException {
- super(resourceResolver, node.getPath(), node, dynamicClassLoader, new PathMapperImpl());
+ super(resourceResolver, node.getPath(), null, node, dynamicClassLoader, new PathMapperImpl());
}
}
Modified: sling/trunk/bundles/resourceresolver/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/pom.xml?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/pom.xml (original)
+++ sling/trunk/bundles/resourceresolver/pom.xml Mon Feb 9 16:00:52 2015
@@ -110,7 +110,7 @@
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.api</artifactId>
- <version>2.8.0</version>
+ <version>2.8.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverImpl.java Mon Feb 9 16:00:52 2015
@@ -19,6 +19,7 @@
package org.apache.sling.resourceresolver.impl;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
@@ -54,6 +55,7 @@ import org.apache.sling.resourceresolver
import org.apache.sling.resourceresolver.impl.helper.URI;
import org.apache.sling.resourceresolver.impl.helper.URIException;
import org.apache.sling.resourceresolver.impl.mapping.MapEntry;
+import org.apache.sling.resourceresolver.impl.tree.params.ParsedParameters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,6 +65,8 @@ public class ResourceResolverImpl extend
/** Default logger */
private final Logger logger = LoggerFactory.getLogger(ResourceResolverImpl.class);
+ private static final Map<String, String> EMPTY_PARAMETERS = Collections.emptyMap();
+
private static final String MANGLE_NAMESPACE_IN_SUFFIX = "_";
private static final String MANGLE_NAMESPACE_IN_PREFIX = "/_";
@@ -311,8 +315,10 @@ public class ResourceResolverImpl extend
Resource res = null;
for (int i = 0; res == null && i < realPathList.length; i++) {
- final String realPath = realPathList[i];
-
+ final ParsedParameters parsedPath = new ParsedParameters(realPathList[i]);
+ final String realPath = parsedPath.getRawPath();
+
+
// first check whether the requested resource is a StarResource
if (StarResource.appliesTo(realPath)) {
logger.debug("resolve: Mapped path {} is a Star Resource", realPath);
@@ -324,24 +330,28 @@ public class ResourceResolverImpl extend
// let's check it with a direct access first
logger.debug("resolve: Try absolute mapped path {}", realPath);
- res = resolveInternal(realPath);
+ res = resolveInternal(realPath, parsedPath.getParameters());
} else {
final String[] searchPath = getSearchPath();
for (int spi = 0; res == null && spi < searchPath.length; spi++) {
logger.debug("resolve: Try relative mapped path with search path entry {}", searchPath[spi]);
- res = resolveInternal(searchPath[spi] + realPath);
+ res = resolveInternal(searchPath[spi] + realPath, parsedPath.getParameters());
}
}
}
+ if (res != null) {
+ res.getResourceMetadata().setParameterMap(parsedPath.getParameters());
+ }
}
// if no resource has been found, use a NonExistingResource
if (res == null) {
- final String resourcePath = ensureAbsPath(realPathList[0]);
+ final ParsedParameters parsedPath = new ParsedParameters(realPathList[0]);
+ final String resourcePath = ensureAbsPath(parsedPath.getRawPath());
logger.debug("resolve: Path {} does not resolve, returning NonExistingResource at {}", absPath, resourcePath);
res = new NonExistingResource(this, resourcePath);
@@ -354,6 +364,7 @@ public class ResourceResolverImpl extend
if (index != -1) {
res.getResourceMetadata().setResolutionPathInfo(resourcePath.substring(index));
}
+ res.getResourceMetadata().setParameterMap(parsedPath.getParameters());
} else {
logger.debug("resolve: Path {} resolves to Resource {}", absPath, res);
}
@@ -418,7 +429,8 @@ public class ResourceResolverImpl extend
}
- final Resource res = resolveInternal(mappedPath);
+ ParsedParameters parsed = new ParsedParameters(mappedPath);
+ final Resource res = resolveInternal(parsed.getRawPath(), parsed.getParameters());
if (res != null) {
@@ -602,21 +614,39 @@ public class ResourceResolverImpl extend
String absolutePath = path;
if (absolutePath != null && !absolutePath.startsWith("/") && base != null) {
- absolutePath = base.getPath() + "/" + absolutePath;
+ absolutePath = appendToPath(base.getPath(), absolutePath);
}
final Resource result = getResourceInternal(absolutePath);
return result;
}
+ /**
+ * Methods concatenates two paths. If the first path contains parameters separated semicolon, they are
+ * moved at the end of the result.
+ *
+ * @param pathWithParameters
+ * @param segmentToAppend
+ * @return
+ */
+ private static String appendToPath(final String pathWithParameters, final String segmentToAppend) {
+ final ParsedParameters parsed = new ParsedParameters(pathWithParameters);
+ if (parsed.getParametersString() == null) {
+ return String.format("%s/%s", parsed.getRawPath(), segmentToAppend);
+ } else {
+ return String.format("%s/%s%s", parsed.getRawPath(), segmentToAppend, parsed.getParametersString());
+ }
+ }
+
private Resource getResourceInternal(String path) {
Resource result = null;
if ( path != null ) {
// if the path is absolute, normalize . and .. segments and get res
if (path.startsWith("/")) {
- path = ResourceUtil.normalize(path);
- result = (path != null) ? getAbsoluteResourceInternal(path, false) : null;
+ ParsedParameters parsedPath = new ParsedParameters(path);
+ path = ResourceUtil.normalize(parsedPath.getRawPath());
+ result = (path != null) ? getAbsoluteResourceInternal(path, parsedPath.getParameters(), false) : null;
if (result != null) {
result = this.factory.getResourceDecoratorTracker().decorate(result);
}
@@ -817,14 +847,14 @@ public class ResourceResolverImpl extend
* the part of the <code>absPath</code> which has been cut off by
* the {@link ResourcePathIterator} to resolve the resource.
*/
- private Resource resolveInternal(final String absPath) {
+ private Resource resolveInternal(final String absPath, final Map<String, String> parameters) {
Resource resource = null;
String curPath = absPath;
try {
final ResourcePathIterator it = new ResourcePathIterator(absPath);
while (it.hasNext() && resource == null) {
curPath = it.next();
- resource = getAbsoluteResourceInternal(curPath, true);
+ resource = getAbsoluteResourceInternal(curPath, parameters, true);
}
} catch (final Exception ex) {
throw new SlingException("Problem trying " + curPath + " for request path " + absPath, ex);
@@ -845,7 +875,7 @@ public class ResourceResolverImpl extend
// no direct resource found, so we have to drill down into the
// resource tree to find a match
- resource = getAbsoluteResourceInternal("/", true);
+ resource = getAbsoluteResourceInternal("/", parameters, true);
final StringBuilder resolutionPath = new StringBuilder();
final StringTokenizer tokener = new StringTokenizer(absPath, "/");
while (resource != null && tokener.hasMoreTokens()) {
@@ -904,7 +934,7 @@ public class ResourceResolverImpl extend
} else {
path = parent.getPath() + '/' + childName;
}
- Resource child = getAbsoluteResourceInternal( ResourceUtil.normalize(path), true );
+ Resource child = getAbsoluteResourceInternal( ResourceUtil.normalize(path), EMPTY_PARAMETERS, true );
if (child != null) {
final String alias = ResourceResolverContext.getProperty(child, PROP_REDIRECT_INTERNAL);
if (alias != null) {
@@ -932,7 +962,7 @@ public class ResourceResolverImpl extend
} else {
aliasPath = parent.getPath() + '/' + aliasName;
}
- final Resource aliasedChild = getAbsoluteResourceInternal( ResourceUtil.normalize(aliasPath), true );
+ final Resource aliasedChild = getAbsoluteResourceInternal( ResourceUtil.normalize(aliasPath), EMPTY_PARAMETERS, true );
logger.debug("getChildInternal: Found Resource {} with alias {} to use", aliasedChild, childName);
return aliasedChild;
}
@@ -948,7 +978,7 @@ public class ResourceResolverImpl extend
for (final String alias : aliases) {
if (childName.equals(alias)) {
logger.debug("getChildInternal: Found Resource {} with alias {} to use", child, childName);
- final Resource aliasedChild = getAbsoluteResourceInternal( ResourceUtil.normalize(child.getPath()) , true);
+ final Resource aliasedChild = getAbsoluteResourceInternal( ResourceUtil.normalize(child.getPath()) , EMPTY_PARAMETERS, true);
return aliasedChild;
}
}
@@ -965,9 +995,9 @@ public class ResourceResolverImpl extend
/**
* Creates a resource with the given path if existing
*/
- private Resource getAbsoluteResourceInternal(final String path, final boolean isResolve) {
+ private Resource getAbsoluteResourceInternal(final String path, final Map<String, String> parameters, final boolean isResolve) {
- final Resource resource = this.factory.getRootProviderEntry().getResource(this.context, this, path ,isResolve);
+ final Resource resource = this.factory.getRootProviderEntry().getResource(this.context, this, path, parameters, isResolve);
if (resource != null) {
resource.getResourceMetadata().setResolutionPath(path);
return resource;
Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceIterator.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceIterator.java?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceIterator.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/helper/ResourceIterator.java Mon Feb 9 16:00:52 2015
@@ -19,6 +19,7 @@
package org.apache.sling.resourceresolver.impl.helper;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -218,7 +219,7 @@ public class ResourceIterator implements
if (!visited.contains(resPath)) {
final ResourceResolver rr = parentResource.getResourceResolver();
final Resource res = rpw.getResourceFromProviders(this.resourceResolverContext, rr,
- resPath);
+ resPath, Collections.<String,String>emptyMap());
if (res == null) {
if (!delayed.containsKey(resPath)) {
delayed.put(
Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ProviderHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ProviderHandler.java?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ProviderHandler.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ProviderHandler.java Mon Feb 9 16:00:52 2015
@@ -341,7 +341,7 @@ public abstract class ProviderHandler im
/**
* @see ResourceProvider#getResource(ResourceResolver, String)
*/
- public abstract Resource getResource(final ResourceResolverContext ctx, final ResourceResolver resourceResolver, final String path);
+ public abstract Resource getResource(final ResourceResolverContext ctx, final ResourceResolver resourceResolver, final String path, final Map<String, String> parameters);
/**
* @see ResourceProvider#listChildren(Resource)
Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderEntry.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderEntry.java?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderEntry.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderEntry.java Mon Feb 9 16:00:52 2015
@@ -37,6 +37,7 @@ import org.apache.sling.api.resource.Res
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.SyntheticResource;
import org.apache.sling.resourceresolver.impl.helper.ResourceResolverContext;
+import org.apache.sling.resourceresolver.impl.tree.params.ParsedParameters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -123,6 +124,7 @@ public class ResourceProviderEntry imple
*
* @param path
* The path to the resource to return.
+ * @param parameters
* @return The resource for the path or <code>null</code> if no resource can
* be found.
* @throws org.apache.sling.api.SlingException
@@ -131,8 +133,9 @@ public class ResourceProviderEntry imple
public Resource getResource(final ResourceResolverContext ctx,
final ResourceResolver resourceResolver,
final String path,
+ final Map<String, String> parameters,
final boolean isResolve) {
- return getInternalResource(ctx, resourceResolver, path, isResolve);
+ return getInternalResource(ctx, resourceResolver, path, parameters, isResolve);
}
// ------------------ Map methods, here so that we can delegate 2 maps
@@ -299,11 +302,13 @@ public class ResourceProviderEntry imple
* @param ctx The resource resolver context
* @param resourceResolver the ResourceResolver.
* @param fullPath the Full path
+ * @param parameters
* @return null if no resource was found, a resource if one was found.
*/
private Resource getInternalResource(final ResourceResolverContext ctx,
final ResourceResolver resourceResolver,
final String fullPath,
+ final Map<String, String> parameters,
final boolean isResolve) {
try {
@@ -323,7 +328,7 @@ public class ResourceProviderEntry imple
for (final ProviderHandler rp : rps) {
boolean foundFallback = false;
- final Resource resource = rp.getResource(ctx, resourceResolver, fullPath);
+ final Resource resource = rp.getResource(ctx, resourceResolver, fullPath, parameters);
if (resource != null) {
if ( resource.getResourceMetadata() != null && resource.getResourceMetadata().get(ResourceMetadata.INTERNAL_CONTINUE_RESOLVING) != null ) {
if ( logger.isDebugEnabled() ) {
@@ -347,7 +352,7 @@ public class ResourceProviderEntry imple
}
// resolve against this one
- final Resource resource = getResourceFromProviders(ctx, resourceResolver, fullPath);
+ final Resource resource = getResourceFromProviders(ctx, resourceResolver, fullPath, parameters);
if (resource != null) {
return resource;
}
@@ -383,13 +388,14 @@ public class ResourceProviderEntry imple
public Resource getResourceFromProviders(final ResourceResolverContext ctx,
final ResourceResolver resourceResolver,
- final String fullPath) {
+ final String fullPath,
+ final Map<String, String> parameters) {
Resource fallbackResource = null;
final ProviderHandler[] rps = getResourceProviders();
for (final ProviderHandler rp : rps) {
boolean foundFallback = false;
- final Resource resource = rp.getResource(ctx, resourceResolver, fullPath);
+ final Resource resource = rp.getResource(ctx, resourceResolver, fullPath, parameters);
if (resource != null) {
if ( resource.getResourceMetadata() != null && resource.getResourceMetadata().get(ResourceMetadata.INTERNAL_CONTINUE_RESOLVING) != null ) {
logger.debug("Resolved Base {} using {} - continue resolving flag is set!", fullPath, rp);
Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderFactoryHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderFactoryHandler.java?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderFactoryHandler.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderFactoryHandler.java Mon Feb 9 16:00:52 2015
@@ -22,7 +22,9 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest;
+import org.apache.commons.collections.MapUtils;
import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.ParametrizableResourceProvider;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceProvider;
import org.apache.sling.api.resource.ResourceProviderFactory;
@@ -101,10 +103,16 @@ public class ResourceProviderFactoryHand
/**
* @see ResourceProvider#getResource(ResourceResolver, String)
*/
- public Resource getResource(final ResourceResolverContext ctx, final ResourceResolver resourceResolver, final String path) {
+ public Resource getResource(final ResourceResolverContext ctx, final ResourceResolver resourceResolver, final String path, final Map<String, String> parameters) {
final ResourceProvider rp = this.getResourceProvider(ctx);
if ( rp != null ) {
- return getReadableResource(ctx, rp.getResource(resourceResolver, path) );
+ final Resource resource;
+ if (MapUtils.isNotEmpty(parameters) && rp instanceof ParametrizableResourceProvider) {
+ resource = ((ParametrizableResourceProvider) rp).getResource(resourceResolver, path, parameters);
+ } else {
+ resource = rp.getResource(resourceResolver, path);
+ }
+ return getReadableResource(ctx, resource);
}
return null;
}
Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderHandler.java?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderHandler.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/ResourceProviderHandler.java Mon Feb 9 16:00:52 2015
@@ -20,6 +20,8 @@ package org.apache.sling.resourceresolve
import java.util.Iterator;
import java.util.Map;
+import org.apache.commons.collections.MapUtils;
+import org.apache.sling.api.resource.ParametrizableResourceProvider;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceProvider;
import org.apache.sling.api.resource.ResourceResolver;
@@ -46,8 +48,14 @@ public class ResourceProviderHandler ext
/**
* @see ResourceProvider#getResource(ResourceResolver, String)
*/
- public Resource getResource(final ResourceResolverContext ctx, final ResourceResolver resourceResolver, final String path) {
- return getReadableResource(ctx, this.resourceProvider.getResource(resourceResolver, path) );
+ public Resource getResource(final ResourceResolverContext ctx, final ResourceResolver resourceResolver, final String path, final Map<String, String> parameters) {
+ final Resource resource;
+ if (MapUtils.isNotEmpty(parameters) && this.resourceProvider instanceof ParametrizableResourceProvider) {
+ resource = ((ParametrizableResourceProvider)this.resourceProvider).getResource(resourceResolver, path, parameters);
+ } else {
+ resource = this.resourceProvider.getResource(resourceResolver, path);
+ }
+ return getReadableResource(ctx, resource);
}
/**
Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/params/ParametersParser.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/params/ParametersParser.java?rev=1658445&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/params/ParametersParser.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/params/ParametersParser.java Mon Feb 9 16:00:52 2015
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sling.resourceresolver.impl.tree.params;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+class ParametersParser {
+
+ private enum ParamsState {
+ INIT, NAME, EQUALS, VALUE, QUOTED_VALUE, QUOTE_END
+ }
+
+ private StringBuilder name;
+
+ private StringBuilder value;
+
+ private Map<String, String> parameters = new LinkedHashMap<String, String>();
+
+ private boolean invalid;
+
+ /**
+ * Parses parameters string, eg.: {@code ;x=123;a='1.0'}. The result of the method is available in
+ * {@link #parameters} and {@link #invalid}.
+ *
+ * @param chars Array containing path with parameters.
+ * @param from Index of the first character of the parameters substring (it must be a semicolon).
+ * @param dotAllowed If true, the dot in parameter value won't stop parsing.
+ * @return Index of the first character not related to parameters.
+ */
+ public int parseParameters(final char[] chars, final int from, final boolean dotAllowed) {
+ resetCurrentParameter();
+ parameters.clear();
+ invalid = false;
+
+ ParamsState state = ParamsState.INIT;
+ for (int i = from; i <= chars.length; i++) {
+ final char c;
+ if (i == chars.length) {
+ c = 0;
+ } else {
+ c = chars[i];
+ }
+ switch (state) {
+ case INIT:
+ if (c == ';') {
+ state = ParamsState.NAME;
+ } else if (c == '.' || c == '/' || c == 0) {
+ invalid = true;
+ return i;
+ }
+ break;
+
+ case NAME:
+ if (c == '=') {
+ state = ParamsState.EQUALS;
+ } else if (c == '.' || c == '/' || c == 0) {
+ invalid = true;
+ return i;
+ } else if (c == ';') {
+ resetCurrentParameter();
+ } else {
+ name.append(c);
+ }
+ break;
+
+ case EQUALS:
+ if (c == '\'') {
+ state = ParamsState.QUOTED_VALUE;
+ } else if (c == '.' || c == '/' || c == 0) {
+ addParameter(); // empty one
+ return i;
+ } else if (c == ';') {
+ state = ParamsState.NAME; // empty one
+ addParameter();
+ } else {
+ state = ParamsState.VALUE;
+ value.append(c);
+ }
+ break;
+
+ case QUOTED_VALUE:
+ if (c == '\'') {
+ state = ParamsState.QUOTE_END;
+ addParameter();
+ } else if (c == 0) {
+ invalid = true;
+ return i;
+ } else {
+ value.append(c);
+ }
+ break;
+
+ case VALUE:
+ if (c == ';') {
+ state = ParamsState.NAME;
+ addParameter();
+ } else if ((c == '.' && !dotAllowed) || c == '/' || c == 0) {
+ addParameter();
+ return i;
+ } else {
+ value.append(c);
+ }
+ break;
+
+ case QUOTE_END:
+ if (c == ';') {
+ state = ParamsState.NAME;
+ } else {
+ return i;
+ }
+ }
+ }
+
+ return chars.length;
+ }
+
+ /**
+ * @return Parsed parameters.
+ */
+ public Map<String, String> getParameters() {
+ return parameters;
+ }
+
+ /**
+ * @return True if the {@link #parseParameters(char[], int, boolean)} method failed.
+ */
+ public boolean isInvalid() {
+ return invalid;
+ }
+
+ private void resetCurrentParameter() {
+ name = new StringBuilder();
+ value = new StringBuilder();
+ }
+
+ private void addParameter() {
+ parameters.put(name.toString(), value.toString());
+ name = new StringBuilder();
+ value = new StringBuilder();
+ }
+}
Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/params/ParsedParameters.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/params/ParsedParameters.java?rev=1658445&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/params/ParsedParameters.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/params/ParsedParameters.java Mon Feb 9 16:00:52 2015
@@ -0,0 +1,77 @@
+/*
+ * 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 SF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package org.apache.sling.resourceresolver.impl.tree.params;
+
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Parses path looking for semicolon-separated parameters. Parameters are extracted and exposed as an
+ * immutable map. The path without parameters is available as raw path.
+ *
+ * Parameters should be added immedietaly before or after selectors and extension:
+ * {@code /content/test;v='1.0'.html} or {@code /content/test.html;v=1.0}. Quotes can be used to escape the
+ * parameter value (it is necessary if the value contains dot and parameter is added before extension).
+ *
+ * @author Tomasz Rekawek
+ */
+public class ParsedParameters {
+
+ private final Map<String, String> parameters;
+
+ private final String parametersString;
+
+ private final String path;
+
+ /**
+ * Parse path and create parameters object.
+ *
+ * @param fullPath Path to parse.
+ */
+ public ParsedParameters(final String fullPath) {
+ final PathParser parser = new PathParser();
+ parser.parse(fullPath);
+
+ parametersString = parser.getParametersString();
+ parameters = Collections.unmodifiableMap(parser.getParameters());
+ path = parser.getPath();
+ }
+
+ /**
+ * @return Path with no parameters.
+ */
+ public String getRawPath() {
+ return path;
+ }
+
+ /**
+ * @return Path's substring containing parameters
+ */
+ public String getParametersString() {
+ return parametersString;
+ }
+
+ /**
+ * @return Map of the parameters.
+ */
+ public Map<String, String> getParameters() {
+ return parameters;
+ }
+
+}
Added: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/params/PathParser.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/params/PathParser.java?rev=1658445&view=auto
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/params/PathParser.java (added)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/tree/params/PathParser.java Mon Feb 9 16:00:52 2015
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.sling.resourceresolver.impl.tree.params;
+
+import java.util.Collections;
+import java.util.Map;
+
+class PathParser {
+
+ /**
+ * List of states. V1 and V2 prefixes means variant 1 and 2. In V1, the parameters are added after
+ * selectors and extension: {@code /content/test.sel.html;v=1.0}. In V2 parameters are added before
+ * selectors and extension: {@code /content/test;v='1.0'.sel.html}
+ */
+ private enum ParserState {
+ INIT, V1_EXTENSION, V1_PARAMS, V2_PARAMS, V2_EXTENSION, SUFFIX, INVALID
+ }
+
+ private String rawPath;
+
+ private String parametersString;
+
+ private Map<String, String> parameters;
+
+ /**
+ * @return Path with no parameters.
+ */
+ public String getPath() {
+ return rawPath;
+ }
+
+ /**
+ * @return Path's substring containing parameters
+ */
+ public String getParametersString() {
+ return parametersString;
+ }
+
+ /**
+ * @return Parsed parameters.
+ */
+ public Map<String, String> getParameters() {
+ return parameters;
+ }
+
+ /**
+ * Parses path containing parameters. Results will be available in {@link #rawPath} and {@link parameters}.
+ *
+ * @param path
+ */
+ public void parse(String path) {
+ this.rawPath = path;
+ this.parameters = Collections.emptyMap();
+
+ if (path == null) {
+ return;
+ }
+
+ final char[] chars = path.toCharArray();
+ final ParametersParser parametersParser = new ParametersParser();
+
+ ParserState state = ParserState.INIT;
+ int paramsStart = -1, paramsEnd = -1;
+
+ for (int i = 0; i <= chars.length; i++) {
+ final char c;
+ if (i == chars.length) {
+ c = 0;
+ } else {
+ c = chars[i];
+ }
+
+ switch (state) {
+ case INIT:
+ if (c == '.') {
+ state = ParserState.V1_EXTENSION;
+ } else if (c == ';') {
+ paramsStart = i;
+ i = parametersParser.parseParameters(chars, i, false);
+ paramsEnd = i--;
+ state = parametersParser.isInvalid() ? ParserState.INVALID : ParserState.V2_PARAMS;
+ }
+ break;
+
+ case V1_EXTENSION:
+ if (c == '/') {
+ state = ParserState.SUFFIX;
+ } else if (c == ';') {
+ paramsStart = i;
+ i = parametersParser.parseParameters(chars, i, true);
+ paramsEnd = i--;
+ state = parametersParser.isInvalid() ? ParserState.INVALID : ParserState.V1_PARAMS;
+ }
+ break;
+
+ case V1_PARAMS:
+ if (c == '/') {
+ state = ParserState.SUFFIX;
+ } else if (c == '.') {
+ state = ParserState.INVALID; // no dots after params
+ }
+ break;
+
+ case V2_PARAMS:
+ if (c == '/') {
+ state = ParserState.INVALID; // there was no extension, so no suffix is allowed
+ } else if (c == '.') {
+ state = ParserState.V2_EXTENSION;
+ }
+ break;
+
+ case V2_EXTENSION:
+ if (c == '/') {
+ state = ParserState.SUFFIX;
+ }
+ break;
+
+ case SUFFIX:
+ case INVALID:
+ break;
+ }
+ }
+
+ if (state == ParserState.INVALID) {
+ paramsStart = paramsEnd = -1;
+ } else {
+ cutPath(path, paramsStart, paramsEnd);
+ parameters = parametersParser.getParameters();
+ }
+ }
+
+ private void cutPath(String path, int from, int to) {
+ if (from == -1) {
+ rawPath = path;
+ parametersString = null;
+ } else if (to == -1) {
+ rawPath = path.substring(0, from);
+ parametersString = path.substring(from);
+ } else {
+ rawPath = path.substring(0, from) + path.substring(to);
+ parametersString = path.substring(from, to);
+ }
+ }
+
+
+}
Modified: sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/MockedResourceResolverImplTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/MockedResourceResolverImplTest.java?rev=1658445&r1=1658444&r2=1658445&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/MockedResourceResolverImplTest.java (original)
+++ sling/trunk/bundles/resourceresolver/src/test/java/org/apache/sling/resourceresolver/impl/MockedResourceResolverImplTest.java Mon Feb 9 16:00:52 2015
@@ -17,9 +17,12 @@
*/
package org.apache.sling.resourceresolver.impl;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
@@ -593,13 +596,13 @@ public class MockedResourceResolverImplT
}
Assert.assertEquals(5,i);
}
-
+
@Test
public void testQueryResources() throws LoginException {
final int n = 3;
Mockito.when(queriableResourceProviderA.queryResources(Mockito.any(ResourceResolver.class), Mockito.any(String.class), Mockito.any(String.class)))
.thenReturn(buildValueMapCollection(n, "A_").iterator());
-
+
final ResourceResolver rr = resourceResolverFactory.getResourceResolver(null);
buildResource("/search/test/withchildren", buildChildResources("/search/test/withchildren"), rr, resourceProvider);
final Iterator<Map<String, Object>> it = rr.queryResources("/search", FAKE_QUERY_LANGUAGE);
@@ -607,7 +610,7 @@ public class MockedResourceResolverImplT
for(int i=0; i < n; i++) {
toFind.add("A_" + i);
}
-
+
assertTrue("Expecting non-empty result (" + n + ")", it.hasNext());
while(it.hasNext()) {
final Map<String, Object> m = it.next();
@@ -616,4 +619,25 @@ public class MockedResourceResolverImplT
assertTrue("Expecting no leftovers (" + n + ") in" + toFind, toFind.isEmpty());
}
+ @Test public void test_versions() throws LoginException {
+ ResourceResolver resourceResolver = resourceResolverFactory.getResourceResolver(null);
+
+ Resource resource = resourceResolver.resolve("/content/test.html;v=1.0");
+ Map<String, String> parameters = resource.getResourceMetadata().getParameterMap();
+ assertEquals("/content/test.html", resource.getPath());
+ assertEquals("test.html", resource.getName());
+ assertEquals(Collections.singletonMap("v", "1.0"), parameters);
+
+ resource = resourceResolver.resolve("/content/test;v='1.0'.html");
+ parameters = resource.getResourceMetadata().getParameterMap();
+ assertEquals("/content/test.html", resource.getPath());
+ assertEquals("test.html", resource.getName());
+ assertEquals(Collections.singletonMap("v", "1.0"), parameters);
+
+ buildResource("/single/test/withchildren", buildChildResources("/single/test/withchildren"), resourceResolver, resourceProvider);
+ resource = resourceResolver.getResource("/single/test/withchildren;v='1.0'");
+ assertNotNull(resource);
+ assertEquals("/single/test/withchildren", resource.getPath());
+ assertEquals("withchildren", resource.getName());
+ }
}