Skip to content

Instantly share code, notes, and snippets.

@saulovenancio
Last active April 23, 2021 13:34
Show Gist options
  • Save saulovenancio/2caaaaade50dc6b6331cdd57f31df931 to your computer and use it in GitHub Desktop.
Save saulovenancio/2caaaaade50dc6b6331cdd57f31df931 to your computer and use it in GitHub Desktop.
ContentFragmentLinkRewriterFilter
package com.mysite.commons.filters;
import static com.mysite.commons.utils.JsonUtils.applyFunctionByAttribute;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
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.engine.EngineConstants;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.ConfigurationPolicy;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.mysite.commons.utils.Constants;
import com.mysite.commons.utils.HttpServletResponseCopier;
import com.mysite.commons.utils.fuctions.RewriterContentFragmentLink;
import com.mysite.commons.utils.fuctions.impl.RewriterContentFragmentLinkImpl;
/**
* This filter rewrites link for the Content Fragment list model exporter
*/
@Component(
service = Filter.class,
immediate = true,
configurationPolicy = ConfigurationPolicy.REQUIRE,
property = {
EngineConstants.SLING_FILTER_SCOPE + "=" + EngineConstants.FILTER_SCOPE_REQUEST,
EngineConstants.SLING_FILTER_METHODS + "=GET",
EngineConstants.SLING_FILTER_SELECTORS + "=model",
EngineConstants.SLING_FILTER_EXTENSIONS + "=json"
}
)
@Designate(ocd = ContentFragmentLinkRewriterFilter.Config.class)
public class ContentFragmentLinkRewriterFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(ContentFragmentLinkRewriterFilter.class);
private static final String ELEMENTS_ATTRIBUTE = "elements";
private Config config;
private List<String> resourceTypes;
@Reference
private ResourceResolverFactory resolverFactory;
@ObjectClassDefinition(name = "AEM Content Fragment List Link Rewriter Filter",
description = "Configuration for filter to extend Content Fragment List functionality to rewrite links")
public @interface Config {
@AttributeDefinition(name = "Enabled",
description = "If this filter should not be active, rather try to delete this config. " +
"Only in cases where this cannot be easily accomplished uncheck this option to disable the filter.")
boolean enabled() default false;
@AttributeDefinition(name = "Resource Types",
description = "Resource Types to be evaluated by the filter.")
String[] resourceTypes();
}
@Activate
public void activate(Config config) {
this.config = config;
this.resourceTypes = Arrays.asList(config.resourceTypes());
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// no-op
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
// add author check
if (!(response instanceof SlingHttpServletResponse) || !(request instanceof SlingHttpServletRequest)) {
throw new IllegalStateException("Filter not properly registered as Sling Servlet Filter");
}
if (!config.enabled()) {
logger.debug("Filter disabled");
filterChain.doFilter(request, response);
return;
}
SlingHttpServletRequest slingHttpServletRequest = (SlingHttpServletRequest) request;
Resource currentResource = slingHttpServletRequest.getResource();
String currentResourceType = currentResource.getResourceType();
if (resourceTypes.stream().noneMatch(resourceType -> StringUtils.startsWith(currentResourceType, resourceType))) {
logger.debug("Current resource path {} is not configured to be evaluated", currentResourceType);
filterChain.doFilter(request, response);
return;
}
// Wrap Response Class before servlet gets called
HttpServletResponseCopier responseCopier = new HttpServletResponseCopier((SlingHttpServletResponse) response);
filterChain.doFilter(request, responseCopier);
// externalize links after the servlet finishes
responseCopier.flushBuffer();
//read original response
byte[] responseBytes = responseCopier.getCopy();
String responseString = new String(responseBytes, responseCopier.getCharacterEncoding());
if (StringUtils.isNotEmpty(responseString)) {
//map the response to a json for manipulation
Gson gson = new Gson();
JsonObject responseJsonObj = gson.fromJson(responseString, JsonObject.class);
Map<String, Object> param = new HashMap<>();
param.put(ResourceResolverFactory.SUBSERVICE, this.getClass().getName());
try (ResourceResolver serviceResourceResolver = resolverFactory.getServiceResourceResolver(param)) {
RewriterContentFragmentLink rewriterContentFragmentLink = new RewriterContentFragmentLinkImpl(serviceResourceResolver);
applyFunctionByAttribute(responseJsonObj, rewriterContentFragmentLink, ELEMENTS_ATTRIBUTE);
String jsonAsString = responseJsonObj.toString();
responseCopier.resetBuffer();
responseCopier.getOutputStream().write(jsonAsString.getBytes());
responseCopier.setContentType(Constants.MEDIA_TYPE_APPLICATION_JSON);
responseCopier.setCharacterEncoding(Constants.CHARSET_UTF_8);
}
catch (LoginException e) {
logger.info("Could not get resource resolver for mapping URL: {}", e);
}
}
}
@Override
public void destroy() {
// no-op
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment