May 13, 2020
Estimated Post Reading Time ~

Filters in AEM

Filters are pieces of java code that run on every request made to AEM. A filter will run for EVERY call to aem, this includes images/css/js/json calls and is not bound to a specific application 

Avoid long processing in a filter or the request may timeout.
Filters run on both the author and publishers.
Filters run for both application code and AEM's own calls 

Below is an example of a logging filter that will log debug for all requests for html pages on a publisher
package com.sample.core.filters;

import java.io.IOException;
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.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.sling.SlingFilter;
import org.apache.felix.scr.annotations.sling.SlingFilterScope;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.settings.SlingSettingsService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@SlingFilter (order = - 9999 , scope = SlingFilterScope.REQUEST)
public class LoggerFilter implements Filter {
@Reference
private SlingSettingsService slingSettingsService;
@Reference
private ResourceResolverFactory resourceResolverFactory;
private Logger logger = LoggerFactory.getLogger(ErrorFilter. class );

@Override
public void doFilter( final ServletRequest request, final ServletResponse response, final FilterChain filterChain) throws IOException, ServletException {
final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
if (isPublisher() && isValidPath(slingRequest.getPathInfo(),slingRequest )) {
if (logger.isDebugEnabled()) {
logger.debug( "Processing: " + slingRequest.getPathInfo()); } } filterChain.doFilter(request, response); }
private boolean isValidPath(String path, SlingHttpServletRequest slingRequest) {
return path.contains( ".html" ) && slingRequest.getRequestPathInfo().getResourcePath().startsWith( "/content" ) && !path.contains( "jcr:" ); }
private boolean isPublisher() {
return slingSettingsService != null && slingSettingsService.getRunModes().contains( "publish" ); }
@Override
public void init(FilterConfig filterConfig) {
//Do any initialisation code here } @Override
public void destroy() {
//Tear down any structures/connections here }
}
To define a filter you use the slingfilter annotation
@SlingFilter (order = - 9999 , scope = SlingFilterScope.REQUEST)
The available parameters are
order
defaults to 0
Where in the filter chain your request will run, the lower the number the earlier it will run in the filter chain
scope
defaults to REQUEST
An array of possible scope filters
REQUEST
Runs the filter once for every request
COMPONENT
Runs the filter once for every component on the page
ERROR
Runs when the code calls HttpServletResponse.sendError or an uncaught Throwable
INCLUDE
Runs when the code calls RequestDispatcher.include
FORWARD
Runs when the code calls requestDispatcher.forward
generateComponent
defaults to true
Generates an AEM component for the filter so that the filter can be found in the system console or bound to more code
generateService
defaults to true
Generates an AEM service for the filter so that the filter can be found in the system console or bound to more code
name
defaults to ""
The name of the filter
metatype
defaults to false
Generates a metattype service
label
defaults to ""
This is the title of the service in the system console
description
defaults to ""
This is the description of the service in the system console
The main method in the Filter interface is the doFilter method
@Override
public void doFilter( final ServletRequest request, final ServletResponse response, final FilterChain filterChain) throws IOException, ServletException {
final SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
if (isPublisher() && isValidPath(slingRequest.getPathInfo(),slingRequest )) {
if (logger.isDebugEnabled()) {
logger.debug( "Processing: " + slingRequest.getPathInfo()); } }
filterChain.doFilter(request, response);
}  

This is where all of the logic is processed, it is then the responsibility of the filter to either call the next filter in the chain or end. If the filter writes to the ServletResponse it is recommended to not continue to the next filter as this may cause problems for later filters or services.
As the call to the filterChain is in the code, the filter can either do it's processing on the way in or the way out.

Filter chain
As you can see in this example filter 3 doesn't call any more filters and the filter chain works back up to the top.
AEM comes with a large number of filters that will run on your code by default, these include filters for security handling, url redirection, vanity url's and many more.
Try to avoid filters like the one above that will log on every request.



By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.