Author: radu Date: Fri Jan 20 09:07:42 2017 New Revision: 1779585 URL: http://svn.apache.org/viewvc?rev=1779585&view=rev Log: SLING-6476 - [HTL] data-sly-resource transforms resources with dots in their paths to SyntheticResources
* check if the resource identified by the path exists so that we don’t run path analysis which on it, which might transform it into a SyntheticResource Added: sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/apps/sightly/scripts/renderer/ sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/apps/sightly/scripts/renderer/renderer.html sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/apps/sightly/scripts/renderer/renderer.js Modified: sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/ResourceRuntimeExtension.java sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/apps/sightly/scripts/resource/resource.html sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/sightly.json sling/trunk/bundles/scripting/sightly/testing/src/test/java/org/apache/sling/scripting/sightly/it/SlingSpecificsSightlyIT.java Modified: sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/ResourceRuntimeExtension.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/ResourceRuntimeExtension.java?rev=1779585&r1=1779584&r2=1779585&view=diff ============================================================================== --- sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/ResourceRuntimeExtension.java (original) +++ sling/trunk/bundles/scripting/sightly/engine/src/main/java/org/apache/sling/scripting/sightly/impl/engine/extension/ResourceRuntimeExtension.java Fri Jan 20 09:07:42 2017 @@ -40,6 +40,7 @@ import org.apache.sling.scripting.sightl import org.apache.sling.scripting.sightly.extension.RuntimeExtension; import org.apache.sling.scripting.sightly.impl.utils.BindingsUtils; import org.apache.sling.scripting.sightly.render.RenderContext; +import org.apache.sling.scripting.sightly.render.RuntimeObjectModel; import org.osgi.service.component.annotations.Component; /** @@ -74,28 +75,49 @@ public class ResourceRuntimeExtension im final Bindings bindings = renderContext.getBindings(); SlingHttpServletRequest request = BindingsUtils.getRequest(bindings); Map originalAttributes = ExtensionUtils.setRequestAttributes(request, (Map)options.remove(OPTION_REQUEST_ATTRIBUTES)); - String resourceType = coerceString(getAndRemoveOption(opts, OPTION_RESOURCE_TYPE)); + RuntimeObjectModel runtimeObjectModel = renderContext.getObjectModel(); + String resourceType = runtimeObjectModel.toString(getAndRemoveOption(opts, OPTION_RESOURCE_TYPE)); StringWriter writer = new StringWriter(); PrintWriter printWriter = new PrintWriter(writer); if (pathObj instanceof Resource) { - Resource includeRes = (Resource) pathObj; - Map<String, String> dispatcherOptionsMap = handleSelectors(bindings, new LinkedHashSet<String>(), opts); + Resource includedResource = (Resource) pathObj; + Map<String, String> dispatcherOptionsMap = handleSelectors(request, new LinkedHashSet<String>(), opts, runtimeObjectModel); String dispatcherOptions = createDispatcherOptions(dispatcherOptionsMap); - includeResource(bindings, printWriter, includeRes, dispatcherOptions, resourceType); + includeResource(bindings, printWriter, includedResource, dispatcherOptions, resourceType); } else { - PathInfo pathInfo = new PathInfo(coerceString(pathObj)); - String finalPath = buildPath(pathInfo.path, opts, BindingsUtils.getResource(bindings)); - Map<String, String> dispatcherOptionsMap = handleSelectors(bindings, pathInfo.selectors, opts); - String dispatcherOptions = createDispatcherOptions(dispatcherOptionsMap); - includeResource(bindings, printWriter, finalPath, dispatcherOptions, resourceType); + String includePath = runtimeObjectModel.toString(pathObj); + // build path completely + includePath = buildPath(includePath, options, request.getResource()); + if (includePath != null) { + // check if path identifies an existing resource + Resource includedResource = request.getResourceResolver().getResource(includePath); + PathInfo pathInfo; + if (includedResource != null) { + Map<String, String> dispatcherOptionsMap = + handleSelectors(request, new LinkedHashSet<String>(), opts, runtimeObjectModel); + String dispatcherOptions = createDispatcherOptions(dispatcherOptionsMap); + includeResource(bindings, printWriter, includedResource, dispatcherOptions, resourceType); + } else { + // analyse path and decompose potential selectors from the path + pathInfo = new PathInfo(includePath); + Map<String, String> dispatcherOptionsMap = handleSelectors(request, pathInfo.selectors, opts, runtimeObjectModel); + String dispatcherOptions = createDispatcherOptions(dispatcherOptionsMap); + includeResource(bindings, printWriter, pathInfo.path, dispatcherOptions, resourceType); + } + } else { + // use the current resource + Map<String, String> dispatcherOptionsMap = handleSelectors(request, new LinkedHashSet<String>(), opts, runtimeObjectModel); + String dispatcherOptions = createDispatcherOptions(dispatcherOptionsMap); + includeResource(bindings, printWriter, request.getResource(), dispatcherOptions, resourceType); + } } ExtensionUtils.setRequestAttributes(request, originalAttributes); return writer.toString(); } - private Map<String, String> handleSelectors(Bindings bindings, Set<String> selectors, Map<String, Object> options) { + private Map<String, String> handleSelectors(SlingHttpServletRequest request, Set<String> selectors, Map<String, Object> options, + RuntimeObjectModel runtimeObjectModel) { if (selectors.isEmpty()) { - SlingHttpServletRequest request = BindingsUtils.getRequest(bindings); selectors.addAll(Arrays.asList(request.getRequestPathInfo().getSelectors())); } Map<String, String> dispatcherOptionsMap = new HashMap<>(); @@ -104,13 +126,13 @@ public class ResourceRuntimeExtension im if (options.containsKey(OPTION_SELECTORS)) { Object selectorsObject = getAndRemoveOption(options, OPTION_SELECTORS); selectors.clear(); - addSelectors(selectors, selectorsObject); + addSelectors(selectors, selectorsObject, runtimeObjectModel); dispatcherOptionsMap.put(OPTION_ADD_SELECTORS, getSelectorString(selectors)); dispatcherOptionsMap.put(OPTION_REPLACE_SELECTORS, " "); } if (options.containsKey(OPTION_ADD_SELECTORS)) { Object selectorsObject = getAndRemoveOption(options, OPTION_ADD_SELECTORS); - addSelectors(selectors, selectorsObject); + addSelectors(selectors, selectorsObject, runtimeObjectModel); dispatcherOptionsMap.put(OPTION_ADD_SELECTORS, getSelectorString(selectors)); dispatcherOptionsMap.put(OPTION_REPLACE_SELECTORS, " "); } @@ -124,7 +146,7 @@ public class ResourceRuntimeExtension im } } else if (selectorsObject instanceof Object[]) { for (Object s : (Object[]) selectorsObject) { - String selector = coerceString(s); + String selector = runtimeObjectModel.toString(s); if (StringUtils.isNotEmpty(selector)) { selectors.remove(selector); } @@ -143,14 +165,14 @@ public class ResourceRuntimeExtension im return dispatcherOptionsMap; } - private void addSelectors(Set<String> selectors, Object selectorsObject) { + private void addSelectors(Set<String> selectors, Object selectorsObject, RuntimeObjectModel runtimeObjectModel) { if (selectorsObject instanceof String) { String selectorString = (String) selectorsObject; String[] parts = selectorString.split("\\."); selectors.addAll(Arrays.asList(parts)); } else if (selectorsObject instanceof Object[]) { for (Object s : (Object[]) selectorsObject) { - String selector = coerceString(s); + String selector = runtimeObjectModel.toString(s); if (StringUtils.isNotEmpty(selector)) { selectors.add(selector); } @@ -158,7 +180,7 @@ public class ResourceRuntimeExtension im } } - private String buildPath(Object pathObj, Map<String, Object> options, Resource currentResource) { + private String buildPath(String path, Map<String, Object> options, Resource currentResource) { String prependPath = getOption(OPTION_PREPEND_PATH, options, StringUtils.EMPTY); if (prependPath == null) { prependPath = StringUtils.EMPTY; @@ -171,7 +193,6 @@ public class ResourceRuntimeExtension im prependPath += "/"; } } - String path = coerceString(pathObj); path = getOption(OPTION_PATH, options, StringUtils.isNotEmpty(path) ? path : StringUtils.EMPTY); String appendPath = getOption(OPTION_APPEND_PATH, options, StringUtils.EMPTY); if (appendPath == null) { @@ -211,13 +232,6 @@ public class ResourceRuntimeExtension im return buffer.toString(); } - private String coerceString(Object obj) { - if (obj instanceof String) { - return (String) obj; - } - return null; - } - private String getOption(String option, Map<String, Object> options, String defaultValue) { if (options.containsKey(option)) { return (String) options.get(option); @@ -229,15 +243,27 @@ public class ResourceRuntimeExtension im return options.remove(property); } - private void includeResource(final Bindings bindings, PrintWriter out, String script, String dispatcherOptions, String resourceType) { - if (StringUtils.isEmpty(script)) { + private String getSelectorString(Set<String> selectors) { + StringBuilder sb = new StringBuilder(); + int i = 0; + for (String s : selectors) { + sb.append(s); + if (i < selectors.size() - 1) { + sb.append("."); + i++; + } + } + return sb.toString(); + } + + private void includeResource(final Bindings bindings, PrintWriter out, String path, String dispatcherOptions, String resourceType) { + if (StringUtils.isEmpty(path)) { throw new SightlyException("Resource path cannot be empty"); } else { SlingHttpServletRequest request = BindingsUtils.getRequest(bindings); - script = normalizePath(request, script); - Resource includeRes = request.getResourceResolver().resolve(script); + Resource includeRes = request.getResourceResolver().resolve(path); if (ResourceUtil.isNonExistingResource(includeRes)) { - includeRes = new SyntheticResource(request.getResourceResolver(), script, resourceType); + includeRes = new SyntheticResource(request.getResourceResolver(), path, resourceType); } includeResource(bindings, out, includeRes, dispatcherOptions, resourceType); } @@ -266,13 +292,6 @@ public class ResourceRuntimeExtension im } } - private String normalizePath(SlingHttpServletRequest request, String path) { - if (!path.startsWith("/")) { - path = request.getResource().getPath() + "/" + path; - } - return ResourceUtil.normalize(path); - } - private class PathInfo { private String path; private Set<String> selectors; @@ -286,41 +305,28 @@ public class ResourceRuntimeExtension im this.path = path.replace("." + selectorString, ""); } } - } - private Set<String> getSelectorsFromPath(String path) { - Set<String> selectors = new LinkedHashSet<>(); - if (path != null) { - String processingPath = path; - int lastSlashPos = path.lastIndexOf('/'); - if (lastSlashPos > -1) { - processingPath = path.substring(lastSlashPos + 1, path.length()); - } - int dotPos = processingPath.indexOf('.'); - if (dotPos > -1) { - int lastDotPos = processingPath.lastIndexOf('.'); - // We're expecting selectors only when an extension is also present. If there's - // one dot it means we only have the extension - if (lastDotPos > dotPos) { - String selectorString = processingPath.substring(dotPos + 1, lastDotPos); - String[] selectorParts = selectorString.split("\\."); - selectors.addAll(Arrays.asList(selectorParts)); + private Set<String> getSelectorsFromPath(String path) { + Set<String> selectors = new LinkedHashSet<>(); + if (path != null) { + String processingPath = path; + int lastSlashPos = path.lastIndexOf('/'); + if (lastSlashPos > -1) { + processingPath = path.substring(lastSlashPos + 1, path.length()); + } + int dotPos = processingPath.indexOf('.'); + if (dotPos > -1) { + int lastDotPos = processingPath.lastIndexOf('.'); + // We're expecting selectors only when an extension is also present. If there's + // one dot it means we only have the extension + if (lastDotPos > dotPos) { + String selectorString = processingPath.substring(dotPos + 1, lastDotPos); + String[] selectorParts = selectorString.split("\\."); + selectors.addAll(Arrays.asList(selectorParts)); + } } } + return selectors; } - return selectors; - } - - private String getSelectorString(Set<String> selectors) { - StringBuilder sb = new StringBuilder(); - int i = 0; - for (String s : selectors) { - sb.append(s); - if (i < selectors.size() - 1) { - sb.append("."); - i++; - } - } - return sb.toString(); } } Added: sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/apps/sightly/scripts/renderer/renderer.html URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/apps/sightly/scripts/renderer/renderer.html?rev=1779585&view=auto ============================================================================== --- sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/apps/sightly/scripts/renderer/renderer.html (added) +++ sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/apps/sightly/scripts/renderer/renderer.html Fri Jan 20 09:07:42 2017 @@ -0,0 +1,21 @@ +<!--/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ 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. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/--> +<div data-sly-use.renderer="renderer.js" id="${renderer.id}"> + <span class="name">${renderer.name}</span> + <span class="path">${renderer.path}</span> + <span class="synthetic">${renderer.synthetic}</span> +</div> Added: sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/apps/sightly/scripts/renderer/renderer.js URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/apps/sightly/scripts/renderer/renderer.js?rev=1779585&view=auto ============================================================================== --- sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/apps/sightly/scripts/renderer/renderer.js (added) +++ sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/apps/sightly/scripts/renderer/renderer.js Fri Jan 20 09:07:42 2017 @@ -0,0 +1,26 @@ +/******************************************************************************* + * 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. + ******************************************************************************/ +/* globals use, Packages, resource */ +use(function() { + var path = resource.path; + return { + "synthetic": Packages.org.apache.sling.api.resource.ResourceUtil.isSyntheticResource(resource), + "name": resource.name, + "path": path, + "id": path.split('/').join('_').split('.').join('_') + } +}); Modified: sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/apps/sightly/scripts/resource/resource.html URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/apps/sightly/scripts/resource/resource.html?rev=1779585&r1=1779584&r2=1779585&view=diff ============================================================================== --- sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/apps/sightly/scripts/resource/resource.html (original) +++ sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/apps/sightly/scripts/resource/resource.html Fri Jan 20 09:07:42 2017 @@ -1,4 +1,4 @@ -<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +<!--/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~ 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 @@ -15,7 +15,7 @@ ~ KIND, either express or implied. See the License for the ~ specific language governing permissions and limitations ~ under the License. - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/--> <!DOCTYPE html> <html> <head> @@ -29,5 +29,8 @@ <div id="dot-include" data-sly-resource="${ '.' @ selectors='dot'}"></div> <div id="extension-selectors" data-sly-resource="${'/sightly/text.a.b.txt'}"></div> <div id="extension-replaceselectors" data-sly-resource="${'/sightly/text.a.b.txt' @ selectors=['c']}"></div> +<sly data-sly-resource="${'/sightly/resource.with.dots.in.path' @ resourceType='sightly/scripts/renderer'}"/> +<sly data-sly-resource="${'/sightly/nonexistingresource' @ resourceType='sightly/scripts/renderer'}"/> +<sly data-sly-resource="${@ resourceType='sightly/scripts/renderer'}"/> </body> </html> Modified: sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/sightly.json URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/sightly.json?rev=1779585&r1=1779584&r2=1779585&view=diff ============================================================================== --- sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/sightly.json (original) +++ sling/trunk/bundles/scripting/sightly/testing-content/src/main/resources/SLING-INF/sightly.json Fri Jan 20 09:07:42 2017 @@ -64,5 +64,8 @@ "whitespace": { "jcr:primaryType": "nt:unstructured", "sling:resourceType": "/apps/sightly/scripts/whitespace" + }, + "resource.with.dots.in.path": { + "jcr:primaryType": "nt:unstructured" } } Modified: sling/trunk/bundles/scripting/sightly/testing/src/test/java/org/apache/sling/scripting/sightly/it/SlingSpecificsSightlyIT.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/sightly/testing/src/test/java/org/apache/sling/scripting/sightly/it/SlingSpecificsSightlyIT.java?rev=1779585&r1=1779584&r2=1779585&view=diff ============================================================================== --- sling/trunk/bundles/scripting/sightly/testing/src/test/java/org/apache/sling/scripting/sightly/it/SlingSpecificsSightlyIT.java (original) +++ sling/trunk/bundles/scripting/sightly/testing/src/test/java/org/apache/sling/scripting/sightly/it/SlingSpecificsSightlyIT.java Fri Jan 20 09:07:42 2017 @@ -126,6 +126,31 @@ public class SlingSpecificsSightlyIT { } @Test + public void testDataSlyResourceResolution() { + String url = launchpadURL + SLING_RESOURCE; + String pageContent = client.getStringContent(url, 200); + + assertEquals("resource.with.dots.in.path", HTMLExtractor.innerHTML(url, pageContent, "#_sightly_resource_with_dots_in_path span" + + ".name")); + assertEquals("/sightly/resource.with.dots.in.path", HTMLExtractor.innerHTML(url, pageContent, "#_sightly_resource_with_dots_in_path span" + + ".path")); + assertEquals("false", HTMLExtractor.innerHTML(url, pageContent, "#_sightly_resource_with_dots_in_path span" + + ".synthetic")); + + assertEquals("nonexistingresource", HTMLExtractor.innerHTML(url, pageContent, "#_sightly_nonexistingresource span" + + ".name")); + assertEquals("/sightly/nonexistingresource", HTMLExtractor.innerHTML(url, pageContent, "#_sightly_nonexistingresource span" + + ".path")); + assertEquals("true", HTMLExtractor.innerHTML(url, pageContent, "#_sightly_nonexistingresource span.synthetic")); + + assertEquals("resource", HTMLExtractor.innerHTML(url, pageContent, "#_sightly_resource span" + + ".name")); + assertEquals("/sightly/resource", HTMLExtractor.innerHTML(url, pageContent, "#_sightly_resource span" + + ".path")); + assertEquals("false", HTMLExtractor.innerHTML(url, pageContent, "#_sightly_resource span.synthetic")); + } + + @Test public void testDataSlyTemplate() { String url = launchpadURL + SLING_TEMPLATE; String pageContent = client.getStringContent(url, 200);