Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Issue #2446] Don't open new ResourceResolver to resolve clientlib categories #2528

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,7 @@ public static Set<String> getSuperTypes(@NotNull final String resourceType, @Not
Set<String> superTypes = new HashSet<>();
String superType = resourceType;
while (superType != null) {
superType = Optional.ofNullable(resourceResolver.getResource(superType))
.map(Resource::getResourceSuperType)
superType = Optional.ofNullable(resourceResolver.getParentResourceType(superType))
.filter(StringUtils::isNotEmpty)
.orElse(null);
if (superType != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,49 +15,38 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
package com.adobe.cq.wcm.core.components.internal.models.v1;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;

import com.adobe.cq.wcm.core.components.internal.Utils;
import com.adobe.cq.wcm.core.components.models.ClientLibraries;
import com.adobe.cq.wcm.core.components.services.clientLibraries.ClientLibraryLookupService;
import com.adobe.granite.ui.clientlibs.ClientLibrary;
import com.adobe.granite.ui.clientlibs.HtmlLibrary;
import com.adobe.granite.ui.clientlibs.HtmlLibraryManager;
import com.adobe.granite.ui.clientlibs.LibraryType;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.models.annotations.Default;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.OSGiService;
import org.apache.sling.models.annotations.injectorspecific.Self;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.adobe.cq.wcm.core.components.internal.Utils;
import com.adobe.cq.wcm.core.components.models.ClientLibraries;
import com.adobe.granite.ui.clientlibs.ClientLibrary;
import com.adobe.granite.ui.clientlibs.HtmlLibrary;
import com.adobe.granite.ui.clientlibs.HtmlLibraryManager;
import com.adobe.granite.ui.clientlibs.LibraryType;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Model(
adaptables = SlingHttpServletRequest.class,
Expand All @@ -68,12 +57,6 @@ public class ClientLibrariesImpl implements ClientLibraries {

private static final Logger LOG = LoggerFactory.getLogger(ClientLibrariesImpl.class);

/**
* Name of the subservice used to authenticate as in order to be able to read details about components and
* client libraries.
*/
public static final String COMPONENTS_SERVICE = "components-service";

@Self
private SlingHttpServletRequest request;

Expand All @@ -96,12 +79,10 @@ public class ClientLibrariesImpl implements ClientLibraries {

@Inject
@Named(OPTION_ASYNC)
@Nullable
private boolean async;

@Inject
@Named(OPTION_DEFER)
@Nullable
private boolean defer;

@Inject
Expand All @@ -123,7 +104,7 @@ public class ClientLibrariesImpl implements ClientLibraries {
private HtmlLibraryManager htmlLibraryManager;

@OSGiService
ResourceResolverFactory resolverFactory;
ClientLibraryLookupService clientLibrariesService;

private Set<String> resourceTypeSet;
private Pattern pattern;
Expand Down Expand Up @@ -175,13 +156,12 @@ public String getJsAndCssIncludes() {
* Returns the markup for including the client libraries into an HTML page
*
* @param type - the type of the client libraries
*
* @return Markup to include the client libraries
*/
private String getLibIncludes(LibraryType type) {
private String getLibIncludes(@Nullable final LibraryType type) {
StringWriter sw = new StringWriter();
try {
if (categoriesArray == null || categoriesArray.length == 0) {
if (categoriesArray == null || categoriesArray.length == 0) {
LOG.error("No categories detected. Please either specify the categories as a CSV string or a set of resource types for looking them up!");
} else {
PrintWriter out = new PrintWriter(sw);
Expand All @@ -206,30 +186,25 @@ private String getLibIncludes(LibraryType type) {
* Returns the HTML markup with the injected JS/CSS attributes
*
* @param html - the input html
*
* @return HTML with injected JS/CSS attributes
*/
private String getHtmlWithInjectedAttributes(String html) {
StringBuilder jsAttributes = new StringBuilder();
jsAttributes.append(getHtmlAttr(OPTION_ASYNC, async));
jsAttributes.append(getHtmlAttr(OPTION_DEFER, defer));
jsAttributes.append(getHtmlAttr(OPTION_CROSSORIGIN, crossorigin));
jsAttributes.append(getHtmlAttr(OPTION_ONLOAD, onload));
StringBuilder cssAttributes = new StringBuilder();
cssAttributes.append(getHtmlAttr(OPTION_MEDIA, media));
String updatedHtml = StringUtils.replace(html,"<script ", "<script " + jsAttributes.toString());
return StringUtils.replace(updatedHtml,"<link ", "<link " + cssAttributes.toString());
private String getHtmlWithInjectedAttributes(@NotNull final String html) {
String jsAttributes = getHtmlAttr(OPTION_ASYNC, async)
+ getHtmlAttr(OPTION_DEFER, defer)
+ getHtmlAttr(OPTION_CROSSORIGIN, crossorigin)
+ getHtmlAttr(OPTION_ONLOAD, onload);
String updatedHtml = StringUtils.replace(html, "<script ", "<script " + jsAttributes);
return StringUtils.replace(updatedHtml, "<link ", "<link " + getHtmlAttr(OPTION_MEDIA, media));
}

/**
* Returns the HTML fragment for an attribute, based on its name and a flag to include or not
*
* @param name - the name of the attribute
* @param name - the name of the attribute
* @param include - {@code true} to include, {@code false} otherwise
*
* @return Fragment for the attribute
*/
private String getHtmlAttr(String name, boolean include) {
private String getHtmlAttr(@NotNull final String name, boolean include) {
if (include) {
return name + " ";
}
Expand All @@ -239,12 +214,11 @@ private String getHtmlAttr(String name, boolean include) {
/**
* Returns the HTML fragment for an attribute, based on its name and value
*
* @param name - the name of the attribute
* @param name - the name of the attribute
* @param value - the value of the attribute
*
* @return Fragment for the attribute
*/
private String getHtmlAttr(String name, String value) {
private String getHtmlAttr(@NotNull final String name, @Nullable final String value) {
if (StringUtils.isNotEmpty(value)) {
return name + "=\"" + value + "\" ";
}
Expand All @@ -255,7 +229,6 @@ private String getHtmlAttr(String name, String value) {
* Returns a concatenated string of the content of all the client libraries, given a library type.
*
* @param libraryType - the type of the library
*
* @return The concatenated string of the content of all the client libraries
*/
private String getInline(LibraryType libraryType) {
Expand Down Expand Up @@ -283,76 +256,11 @@ private String getInline(LibraryType libraryType) {
*/
@NotNull
protected Set<String> getCategoriesFromComponents() {
try (ResourceResolver resourceResolver = resolverFactory.getServiceResourceResolver(Collections.singletonMap(ResourceResolverFactory.SUBSERVICE, COMPONENTS_SERVICE))) {
Set<String> categories = new HashSet<>();
for (ClientLibrary library : this.getAllClientLibraries(resourceResolver)) {
for (String category : library.getCategories()) {
if (pattern == null || pattern.matcher(category).matches()) {
categories.add(category);
}
}
}
return categories;
} catch (LoginException e) {
LOG.error("Cannot login as a service user", e);
return Collections.emptySet();
}
}

/**
* Gets all of the client libraries.
*
* @param resourceResolver The resource resolver.
* @return Set of all client libraries.
*/
@NotNull
private Set<ClientLibrary> getAllClientLibraries(@NotNull final ResourceResolver resourceResolver) {
Map<String, ClientLibrary> allLibraries = htmlLibraryManager.getLibraries();
Set<ClientLibrary> clientLibraries = new LinkedHashSet<>();
for (String resourceType : getAllResourceTypes(resourceResolver)) {
Resource resource = resourceResolver.getResource(resourceType);
if (resource != null) {
clientLibraries.addAll(getClientLibraries(resource, allLibraries));
}
}
return clientLibraries;
}

/**
* Gets all resource types.
*
* @param resourceResolver The resource resolver.
* @return Set of all resource types under which to search for client libraries.
*/
@NotNull
private Set<String> getAllResourceTypes(@NotNull final ResourceResolver resourceResolver) {
Set<String> allResourceTypes = new LinkedHashSet<>(resourceTypeSet);
if (inherited) {
for (String resourceType : resourceTypeSet) {
allResourceTypes.addAll(Utils.getSuperTypes(resourceType, resourceResolver));
}
}
return allResourceTypes;
}

/**
* Gets a list of client libraries, starting from the given resource
* and diving into its descendants.
*
* @param resource - the given resource, which will be checked to see if it's a client library
* @param allLibraries - Map of all client libraries.
* @return List of client libraries for the given resource.
*/
@NotNull
private static List<ClientLibrary> getClientLibraries(@org.jetbrains.annotations.Nullable final Resource resource,
@NotNull final Map<String, ClientLibrary> allLibraries) {
return Optional.ofNullable(resource)
.map(Resource::getPath)
.map(path -> allLibraries.entrySet().stream()
.filter(entry -> entry.getKey().equals(path) || entry.getKey().startsWith(path + "/"))
.map(Map.Entry::getValue)
.collect(Collectors.toList()))
.orElseGet(Collections::emptyList);
return this.clientLibrariesService.getAllClientLibraries(this.resourceTypeSet, this.inherited, this.request.getResourceResolver()).stream()
.map(ClientLibrary::getCategories)
.flatMap(Arrays::stream)
.filter(category -> pattern == null || pattern.matcher(category).matches())
.collect(Collectors.toSet());
}

}