This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-resourceresolver.git
The following commit(s) were added to refs/heads/master by this push:
new 9ff4836 SLING-7792 - Resource Resolver should return more than one
resolved path if available
9ff4836 is described below
commit 9ff4836d3155b27208418c10aa8bb5965bcc2bf5
Author: Robert Munteanu <[email protected]>
AuthorDate: Fri Aug 17 15:55:15 2018 +0200
SLING-7792 - Resource Resolver should return more than one resolved path
if available
Preserve backwards compatibility with the previous map() implementation
by ensuring that in case an alias and a mapping entry both exist the
mapping entry for the resource path does not take precedence over the
alias.
---
.../impl/mapping/ResourceMapperImpl.java | 64 +++++++++++++---------
.../impl/mapping/ResourceMapperImplTest.java | 21 ++++++-
2 files changed, 58 insertions(+), 27 deletions(-)
diff --git
a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImpl.java
b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImpl.java
index 5610054..0d78a8c 100644
---
a/src/main/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImpl.java
+++
b/src/main/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImpl.java
@@ -87,6 +87,31 @@ public class ResourceMapperImpl implements ResourceMapper {
resolver.checkClosed();
+ // A note on the usage of the 'mappings' variable and the order of the
results
+ //
+ // The API contract of the ResourceMapper does not specify the order
in which the elements are returned
+ // As an implementation detail however the getMapping method picks the
first element of the return value
+ // as the 'winner'.
+ //
+ // Therefore we take care to add the entries in a very particular
order, which preserves backwards
+ // compatibility with the existing implementation. Previously the
order was
+ //
+ // resource path → alias → mapping (with alias potentially being
null)
+ //
+ // To ensure we keep the same behaviour but expose all possible
mappings, we now have the following
+ // flow
+ //
+ // resource path → mapping
+ // resource path → alias
+ // alias → mapping
+ //
+ // After all are processed we reverse the order to preserve the logic
of the old ResourceResolver.map() method (last
+ // found wins) and also make sure that no duplicates are added.
+ //
+ // There is some room for improvement here by using a data structure
that does not need reversing ( ArrayList
+ // .add moves the elements every time ) or reversal of duplicates but
since we will have a small number of
+ // entries ( <= 4 ) the time spent here should be negligible.
+
List<String> mappings = new ArrayList<>();
// 1. parse parameters
@@ -116,23 +141,25 @@ public class ResourceMapperImpl implements ResourceMapper
{
// 2. add the requested path itself
mappings.add(mappedPath);
+ // 3. load mappings from the resource path
+ populateMappingsFromMapEntries(mappings, mappedPath, requestContext);
+
- // 3. load aliases
+ // 4. load aliases
final Resource nonDecoratedResource =
resolver.resolveInternal(parsed.getRawPath(), parsed.getParameters());
if (nonDecoratedResource != null) {
- loadAliasIfApplicable(mappings, nonDecoratedResource);
+ String alias = loadAliasIfApplicable(nonDecoratedResource);
+
+ // 5. load mappings for alias
+ if ( alias != null )
+ mappings.add(alias);
+ populateMappingsFromMapEntries(mappings, alias, requestContext);
}
- // 4. load /etc/map entries
- // populate entries from all entries, including original path and any
found aliases
- for ( String mapped : new ArrayList<>(mappings) )
- populateMappingsFromMapEntries(mappings, mapped, requestContext);
-
-
- // 5. apply context path if needed
+ // 6. apply context path if needed
mappings.replaceAll(new ApplyContextPath(request));
- // 6. set back the fragment query if needed
+ // 7. set back the fragment query if needed
if ( fragmentQuery != null ) {
mappings.replaceAll(new UnaryOperator<String>() {
@Override
@@ -146,24 +173,12 @@ public class ResourceMapperImpl implements ResourceMapper
{
logger.debug("map: Returning URL {} as mapping for path {}", path,
resourcePath);
});
-
- // The API contract of the ResourceMapper does not specify the order
in which the elements are returned
- // As an implementation detail however the getMapping method picks the
first element of the return value
- // as the 'winner'.
- //
- // Therefore we reverse the sorting to preserve the logic of the old
ResourceResolver.map() method (last
- // found wins) and also make sure that no duplicates are added
- //
- // There is some room for improvement here by using a data structure
that does not need reversing ( ArrayList
- // .add moves the elements every time ) or reversal of duplicates but
the expectation is that we have a small
- // number of mappings ( <= 10 ) so the time spent here should be
negligible.
-
Collections.reverse(mappings);
return new LinkedHashSet<>(mappings);
}
- private void loadAliasIfApplicable(List<String> mappings, final Resource
nonDecoratedResource) {
+ private String loadAliasIfApplicable(final Resource nonDecoratedResource) {
//Invoke the decorator for the resolved resource
Resource res = resourceDecorator.decorate(nonDecoratedResource);
@@ -236,7 +251,7 @@ public class ResourceMapperImpl implements ResourceMapper {
logger.debug("map: Alias mapping resolves to path {}", mappedPath);
- mappings.add(mappedPath);
+ return mappedPath;
}
private void populateMappingsFromMapEntries(List<String> mappings, String
mappedPath,
@@ -363,6 +378,5 @@ public class ResourceMapperImpl implements ResourceMapper {
return mappedPath;
}
-
}
}
diff --git
a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImplTest.java
b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImplTest.java
index 6caefa9..58263b6 100644
---
a/src/test/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImplTest.java
+++
b/src/test/java/org/apache/sling/resourceresolver/impl/mapping/ResourceMapperImplTest.java
@@ -87,6 +87,7 @@ public class ResourceMapperImplTest {
resourceProvider.putResource("/here"); // regular page
resourceProvider.putResource("/there", PROP_ALIAS, "alias-value"); //
with alias
resourceProvider.putResource("/somewhere", PROP_ALIAS,
"alias-value-2"); // with alias and also /etc/map
+ resourceProvider.putResource("/there/that"); // parent has alias
// build /etc/map structure
resourceProvider.putResource("/etc");
@@ -179,12 +180,28 @@ public class ResourceMapperImplTest {
public void mapResourceWithAliasAndEtcMap() {
ExpectedMappings.existingResource("/somewhere")
- .singleMapping("http://localhost:8080/everywhere")
- .singleMappingWithRequest("/app/everywhere")
+ .singleMapping("/alias-value-2")
+ .singleMappingWithRequest("/app/alias-value-2")
.allMappings("http://localhost:8080/everywhere", "/alias-value-2",
"/somewhere")
.allMappingsWithRequest("/app/everywhere","/app/alias-value-2",
"/app/somewhere")
.verify(resolver, req);
}
+
+ /**
+ * Validates that a resource with an alias on parent has the parent path
set
+ * to the alias value
+ *
+ * @throws LoginException
+ */
+ @Test
+ public void mapResourceWithAliasOnParent() {
+ ExpectedMappings.existingResource("/there/that")
+ .singleMapping("/alias-value/that")
+ .singleMappingWithRequest("/app/alias-value/that")
+ .allMappings("/alias-value/that", "/there/that")
+ .allMappingsWithRequest("/app/alias-value/that","/app/there/that")
+ .verify(resolver, req);
+ }
static class ExpectedMappings {