Skip to content

Commit adccb07

Browse files
author
Laurentiu Magureanu
authored
CIF-2235: Support different url formats for different store configurations (#792)
* CIF-2235: Add support for CA config url formats * CIF-2235: Fix formatting and test mocking * CIF-2235: Add unit tests * CIF-2235: Reduce duplicate code * CIF-2235: Add url formats datasource * CIF-2235: Update URLProvider interface * CIF-2235: Fix compilation issues + formatting * CIF-2235: Fix merge errors * CIF-2235: Add unit tests * CIF-2235: Improve datasources * CIF-2235: Improve datasource servlets
1 parent 9b713fc commit adccb07

15 files changed

Lines changed: 832 additions & 101 deletions

File tree

bundles/core/src/main/java/com/adobe/cq/commerce/core/components/internal/services/UrlProviderImpl.java

Lines changed: 154 additions & 50 deletions
Large diffs are not rendered by default.

bundles/core/src/main/java/com/adobe/cq/commerce/core/components/internal/services/sitemap/CategoriesSitemapGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ public void generate(Resource sitemapRoot, String name, Sitemap sitemap, Context
155155
// skip root category, and ignored categories
156156
CategoryUrlFormat.Params params = new CategoryUrlFormat.Params(category);
157157
params.setPage(categoryPage.getPath());
158-
String urlStr = externalizer.toExternalCategoryUrl(null, null, params);
158+
String urlStr = externalizer.toExternalCategoryUrl(null, categoryPage, params);
159159
Url url = sitemap.addUrl(urlStr);
160160
if (addLastModified) {
161161
addLastModified(url, category);

bundles/core/src/main/java/com/adobe/cq/commerce/core/components/internal/services/sitemap/ProductsSitemapGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ public void generate(Resource sitemapRoot, String name, Sitemap sitemap, Sitemap
147147
}
148148
ProductUrlFormat.Params params = new ProductUrlFormat.Params(product);
149149
params.setPage(productPage.getPath());
150-
String urlStr = externalizer.toExternalProductUrl(null, null, params);
150+
String urlStr = externalizer.toExternalProductUrl(null, productPage, params);
151151
Url url = sitemap.addUrl(urlStr);
152152
if (addLastModified) {
153153
addLastModified(url, product);

bundles/core/src/main/java/com/adobe/cq/commerce/core/components/internal/services/sitemap/SitemapLinkExternalizerProvider.java

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -93,37 +93,32 @@ private class SlingSitemapLinkExternalizer implements SitemapLinkExternalizer {
9393

9494
@Override
9595
public String toExternalProductUrl(SlingHttpServletRequest request, Page page, ProductUrlFormat.Params params) {
96-
String externalPath = externalize(page, params.getPage());
97-
// if externalized we must not pass page to the url provider as this will overwrite the path again. this will break the specific
98-
// page selection if enabled but for canonical urls we don't want this to be active anyway
99-
if (externalPath != null) {
100-
// make a copy
101-
params = new ProductUrlFormat.Params(params);
102-
params.setPage(externalPath);
103-
return urlProvider.toProductUrl(request, null, params);
96+
String url = urlProvider.toProductUrl(request, page, params);
97+
Resource resolvedResource = resourceResolver.resolve(url);
98+
String externalPath = externalizer.externalize(resolvedResource);
99+
100+
if (externalPath != null && url.startsWith(resolvedResource.getPath())) {
101+
return externalPath + url.substring(resolvedResource.getPath().length());
104102
} else {
105-
return urlProvider.toProductUrl(request, page, params);
103+
// the url does not start with the resource path, it may already be
104+
// externalised?
105+
return url;
106106
}
107107
}
108108

109109
@Override
110110
public String toExternalCategoryUrl(SlingHttpServletRequest request, Page page, CategoryUrlFormat.Params params) {
111-
String externalPath = externalize(page, params.getPage());
112-
// if externalized we must not pass page to the url provider as this will overwrite the path again. this will break the specific
113-
// page selection if enabled but for canonical urls we don't want this to be active anyway
114-
if (externalPath != null) {
115-
// make a copy
116-
params = new CategoryUrlFormat.Params(params);
117-
params.setPage(externalPath);
118-
return urlProvider.toCategoryUrl(request, null, params);
111+
String url = urlProvider.toCategoryUrl(request, page, params);
112+
Resource resolvedResource = resourceResolver.resolve(url);
113+
String externalPath = externalizer.externalize(resolvedResource);
114+
115+
if (externalPath != null && url.startsWith(resolvedResource.getPath())) {
116+
return externalPath + url.substring(resolvedResource.getPath().length());
119117
} else {
120-
return urlProvider.toCategoryUrl(request, page, params);
118+
// the url does not start with the resource path, it may already be
119+
// externalised?
120+
return url;
121121
}
122122
}
123-
124-
private String externalize(Page page, String alternativePagePath) {
125-
Resource pageResource = page != null ? page.adaptTo(Resource.class) : resourceResolver.getResource(alternativePagePath);
126-
return pageResource != null ? externalizer.externalize(pageResource) : null;
127-
}
128123
}
129124
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2+
~ Copyright 2022 Adobe
3+
~
4+
~ Licensed under the Apache License, Version 2.0 (the "License");
5+
~ you may not use this file except in compliance with the License.
6+
~ You may obtain a copy of the License at
7+
~
8+
~ http://www.apache.org/licenses/LICENSE-2.0
9+
~
10+
~ Unless required by applicable law or agreed to in writing, software
11+
~ distributed under the License is distributed on an "AS IS" BASIS,
12+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
~ See the License for the specific language governing permissions and
14+
~ limitations under the License.
15+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
16+
package com.adobe.cq.commerce.core.components.internal.servlets;
17+
18+
import java.util.ArrayList;
19+
import java.util.HashMap;
20+
import java.util.List;
21+
22+
import org.apache.commons.lang3.StringUtils;
23+
import org.apache.sling.api.SlingHttpServletRequest;
24+
import org.apache.sling.api.resource.Resource;
25+
import org.apache.sling.api.resource.ResourceResolver;
26+
import org.apache.sling.api.resource.ValueMap;
27+
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
28+
import org.apache.sling.api.wrappers.ValueMapDecorator;
29+
30+
import com.adobe.granite.ui.components.ds.DataSource;
31+
import com.adobe.granite.ui.components.ds.SimpleDataSource;
32+
import com.adobe.granite.ui.components.ds.ValueMapResource;
33+
34+
public abstract class AbstractPageUrlFormatsServlet extends SlingSafeMethodsServlet {
35+
static final String COMPONENT_NAME_KEY = "component.name";
36+
static final String VALUE_PN = "value";
37+
static final String TEXT_PN = "text";
38+
39+
public DataSource getDataSource(SlingHttpServletRequest request, List<String> predefinedUrlFormats,
40+
List<String> customFormatNames,
41+
String useAsFilter) {
42+
List<Resource> resources = new ArrayList<>();
43+
44+
ValueMap properties = new ValueMapDecorator(new HashMap<>());
45+
properties.put(TEXT_PN, "System default");
46+
properties.put(VALUE_PN, StringUtils.EMPTY);
47+
resources.add(new ValueMapResource(
48+
request.getResourceResolver(), "/" + this.getClass().getCanonicalName() + "/item",
49+
Resource.RESOURCE_TYPE_NON_EXISTING,
50+
properties));
51+
52+
predefinedUrlFormats.forEach(f -> resources.add(
53+
buildValueMapResourceForDefaultFormats(
54+
f, request.getResourceResolver(), useAsFilter)));
55+
56+
customFormatNames.forEach(r -> resources.add(
57+
buildValueMapResourceForCustomFormats(r, request.getResourceResolver(), useAsFilter)));
58+
59+
return new SimpleDataSource(resources.iterator());
60+
}
61+
62+
private Resource buildValueMapResourceForDefaultFormats(String format,
63+
ResourceResolver resourceResolver, String name) {
64+
ValueMap properties = new ValueMapDecorator(new HashMap<>());
65+
properties.put(TEXT_PN, format.replace("\\", ""));
66+
properties.put(VALUE_PN, format);
67+
return new ValueMapResource(resourceResolver, "/" + name + "/item",
68+
Resource.RESOURCE_TYPE_NON_EXISTING,
69+
properties);
70+
}
71+
72+
private Resource buildValueMapResourceForCustomFormats(String formatClassName,
73+
ResourceResolver resourceResolver, String name) {
74+
ValueMap properties = new ValueMapDecorator(new HashMap<>());
75+
properties.put(TEXT_PN, formatClassName);
76+
properties.put(VALUE_PN, formatClassName);
77+
return new ValueMapResource(
78+
resourceResolver, "/" + name + "/item",
79+
Resource.RESOURCE_TYPE_NON_EXISTING,
80+
properties);
81+
}
82+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2+
~ Copyright 2022 Adobe
3+
~
4+
~ Licensed under the Apache License, Version 2.0 (the "License");
5+
~ you may not use this file except in compliance with the License.
6+
~ You may obtain a copy of the License at
7+
~
8+
~ http://www.apache.org/licenses/LICENSE-2.0
9+
~
10+
~ Unless required by applicable law or agreed to in writing, software
11+
~ distributed under the License is distributed on an "AS IS" BASIS,
12+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
~ See the License for the specific language governing permissions and
14+
~ limitations under the License.
15+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
16+
package com.adobe.cq.commerce.core.components.internal.servlets;
17+
18+
import java.util.ArrayList;
19+
import java.util.List;
20+
import java.util.stream.Collectors;
21+
22+
import javax.servlet.Servlet;
23+
24+
import org.apache.sling.api.SlingHttpServletRequest;
25+
import org.apache.sling.api.SlingHttpServletResponse;
26+
import org.osgi.service.component.annotations.Component;
27+
import org.osgi.service.component.annotations.Reference;
28+
import org.osgi.service.component.annotations.ReferenceCardinality;
29+
import org.osgi.service.component.annotations.ReferencePolicy;
30+
import org.osgi.service.component.annotations.ReferencePolicyOption;
31+
32+
import com.adobe.cq.commerce.core.components.internal.services.UrlProviderImpl;
33+
import com.adobe.cq.commerce.core.components.services.urls.CategoryUrlFormat;
34+
import com.adobe.cq.commerce.core.components.services.urls.UrlFormat;
35+
import com.adobe.granite.ui.components.ds.DataSource;
36+
37+
@Component(
38+
service = { Servlet.class },
39+
property = {
40+
"sling.servlet.resourceTypes=" + CategoryPageUrlFormatsServlet.RESOURCE_TYPE,
41+
"sling.servlet.methods=GET",
42+
"sling.servlet.extensions=html"
43+
})
44+
public class CategoryPageUrlFormatsServlet extends AbstractPageUrlFormatsServlet {
45+
static final String RESOURCE_TYPE = "core/cif/components/datasource/categoryurlformats";
46+
static final String PAGE_URL_FORMAT_KEY = "categoryPageUrlFormat";
47+
static final List<String> URL_FORMATS = UrlProviderImpl.DEFAULT_CATEGORY_URL_FORMATS.keySet().stream()
48+
.map(f -> f.replace("#", "\\#"))
49+
.collect(Collectors.toList());
50+
51+
@Reference(
52+
cardinality = ReferenceCardinality.MULTIPLE,
53+
policy = ReferencePolicy.STATIC,
54+
policyOption = ReferencePolicyOption.GREEDY,
55+
target = "("
56+
+ UrlFormat.PROP_USE_AS + "=" + UrlFormat.CATEGORY_PAGE_URL_FORMAT + ")")
57+
private List<UrlFormat> categoryPageUrlFormats;
58+
59+
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY)
60+
private List<CategoryUrlFormat> newCategoryUrlFormat;
61+
62+
@Override
63+
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {
64+
List<String> customFormatNames = new ArrayList<>();
65+
66+
if (newCategoryUrlFormat != null) {
67+
newCategoryUrlFormat.forEach(f -> customFormatNames.add(f.getClass().getName()));
68+
}
69+
70+
if (categoryPageUrlFormats != null) {
71+
categoryPageUrlFormats.forEach(f -> customFormatNames.add(f.getClass().getName()));
72+
}
73+
74+
request.setAttribute(DataSource.class.getName(), getDataSource(request,
75+
URL_FORMATS,
76+
customFormatNames,
77+
PAGE_URL_FORMAT_KEY));
78+
}
79+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2+
~ Copyright 2022 Adobe
3+
~
4+
~ Licensed under the Apache License, Version 2.0 (the "License");
5+
~ you may not use this file except in compliance with the License.
6+
~ You may obtain a copy of the License at
7+
~
8+
~ http://www.apache.org/licenses/LICENSE-2.0
9+
~
10+
~ Unless required by applicable law or agreed to in writing, software
11+
~ distributed under the License is distributed on an "AS IS" BASIS,
12+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
~ See the License for the specific language governing permissions and
14+
~ limitations under the License.
15+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
16+
package com.adobe.cq.commerce.core.components.internal.servlets;
17+
18+
import java.util.ArrayList;
19+
import java.util.List;
20+
import java.util.stream.Collectors;
21+
22+
import javax.servlet.Servlet;
23+
24+
import org.apache.sling.api.SlingHttpServletRequest;
25+
import org.apache.sling.api.SlingHttpServletResponse;
26+
import org.osgi.service.component.annotations.Component;
27+
import org.osgi.service.component.annotations.Reference;
28+
import org.osgi.service.component.annotations.ReferenceCardinality;
29+
import org.osgi.service.component.annotations.ReferencePolicy;
30+
import org.osgi.service.component.annotations.ReferencePolicyOption;
31+
32+
import com.adobe.cq.commerce.core.components.internal.services.UrlProviderImpl;
33+
import com.adobe.cq.commerce.core.components.services.urls.ProductUrlFormat;
34+
import com.adobe.cq.commerce.core.components.services.urls.UrlFormat;
35+
import com.adobe.granite.ui.components.ds.DataSource;
36+
37+
@Component(
38+
service = { Servlet.class },
39+
property = {
40+
"sling.servlet.resourceTypes=" + ProductPageUrlFormatsServlet.RESOURCE_TYPE,
41+
"sling.servlet.methods=GET",
42+
"sling.servlet.extensions=html"
43+
})
44+
public class ProductPageUrlFormatsServlet extends AbstractPageUrlFormatsServlet {
45+
static final String RESOURCE_TYPE = "core/cif/components/datasource/producturlformats";
46+
static final String PAGE_URL_FORMAT_KEY = "productPageUrlFormat";
47+
static final List<String> URL_FORMATS = UrlProviderImpl.DEFAULT_PRODUCT_URL_FORMATS.keySet().stream().map(f -> f.replace(
48+
"#", "\\#")).collect(Collectors.toList());
49+
50+
@Reference(
51+
cardinality = ReferenceCardinality.MULTIPLE,
52+
policy = ReferencePolicy.STATIC,
53+
policyOption = ReferencePolicyOption.GREEDY,
54+
target = "("
55+
+ UrlFormat.PROP_USE_AS + "=" + UrlFormat.PRODUCT_PAGE_URL_FORMAT + ")")
56+
private List<UrlFormat> productPageUrlFormats;
57+
58+
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY)
59+
private List<ProductUrlFormat> newProductUrlFormat;
60+
61+
@Override
62+
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {
63+
List<String> customFormatNames = new ArrayList<>();
64+
65+
if (newProductUrlFormat != null) {
66+
newProductUrlFormat.forEach(f -> customFormatNames.add(f.getClass().getName()));
67+
}
68+
69+
if (productPageUrlFormats != null) {
70+
productPageUrlFormats.forEach(f -> customFormatNames.add(f.getClass().getName()));
71+
}
72+
73+
request.setAttribute(DataSource.class.getName(), getDataSource(request,
74+
URL_FORMATS,
75+
customFormatNames,
76+
PAGE_URL_FORMAT_KEY));
77+
}
78+
79+
}

0 commit comments

Comments
 (0)