Request processing and filters

Magnolia uses the Java filter concept, introduced in the Java Servlet specification version 2.3. A filter captures and processes a request before it reaches a servlet.

Filters typically don’t create responses themselves but provide universal functions that can be attached to any type of servlet page. For more information, see the list of filters.

Life of a request

This diagram shows a typical request process in Magnolia:

Request processing and filter chain in Magnolia

In the diagram you can see the following filters:

  • Context. The first filter in the filter chain is info.magnolia.cms.filters.ContextFilter. It initializes MgnlContext which is local to the request and available on every further filter. The context provides a lot of useful functions.

  • CORS. (Magnolia 6.2.4+) Handles simple and pre-flight requests for Cross-Origin Resource Sharing (CORS)

  • URI security. Checks to see if the active user has permission to access the requested URI.

  • Custom filter. This could be your own filter implementation. For example, check if the URL includes a custom parameter.

  • Cache. info.magnolia.module.cache.filter.CacheFilter manages the Magnolia cache.

    The cache filter checks if a requested resource is already stored in the cache to avoid recreating the resource. If the resource is in the cache, then it’s written to the response and the filter chain stops. If the resource is not found in the cache, then a ResponseWrapper, which not only writes to the standard response, but saves the response, is passed to the chain.

  • CMS filter chain. Next we arrive to the CMS filter chain. It does page rendering and delivery. The filters in this subchain are groups so that they can share a bypass definition.

  • Aggregator. info.magnolia.cms.filters.AggregatorFilter analyzes the request, selects content from the repository and stores it in info.magnolia.cms.core.AggregationState.

  • Rendering. Finally, info.magnolia.rendering.engine.RenderingFilter is responsible for delivering the requested resource. If the requested resource is data (for example, a file), then the data is just copied to the response.

Fulfilling a request

The filter chain calls the doFilter(request, response, chain) of the next filter. If the filter wants to continue the chain, chain.doFilter(request, response) is called.

A filter which can fulfill the request typically has a doFilter(…​) method:

public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException{
    if (this.handle(request, response)) {
        return;
    }
    chain.doFilter(request, response);
  }

There are other filters that do some processing in the request handling.

public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException{
      // preprocessing
      ....
      chain.doFilter(request, response);
      // postprocessing
      ....
  }

Basic filter definition in web.xml

If you look at the web.xml of a Magnolia web application, you see that it only defines one filter (info.magnolia.cms.filters.MgnlMainFilter) and one listener (MgnlServletContextListener):

<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
   <description>Magnolia</description>
   <display-name>magnolia</display-name>
   <distributable/>
   <filter>
      <display-name>Magnolia global filters</display-name>
      <filter-name>magnoliaFilterChain</filter-name>
      <filter-class>info.magnolia.cms.filters.MgnlMainFilter</filter-class>
   </filter>
   <filter-mapping>
      <filter-name>magnoliaFilterChain</filter-name>
      <url-pattern>/*</url-pattern>
      <dispatcher>REQUEST</dispatcher>
      <dispatcher>FORWARD</dispatcher>
      <dispatcher>ERROR</dispatcher>
   </filter-mapping>
   <listener>
      <listener-class>info.magnolia.cms.servlets.MgnlServletContextListener</listener-class>
   </listener>
</web-app>

The listener initializes Magnolia while the filter handles all requests.

Magnolia main filter

info.magnolia.cms.filters.MgnlMainFilter is a single filter which in turn executes a chain of other filters. The other filters are not configured in web.xml but in Magnolia’s config workspace at /server/filters.

Magnolia main filter configuration space

In the filter configuration, you can again have single filters or filter chains. A filter chain consists of a list of single filters represented by child nodes. A filter node has a class property which specifies the implementing class and can optionally have an enabled property.

Filter chains in the filter configuration

If the filter is enabled (default), then the filter is executed. Otherwise the filter is bypassed. A filter or a filter chain can define rules to determine when a filter should be bypassed. The configuration of bypasses is done using voters.

This example shows that the URI for the login form is bypassed in the uriSecurity filter.

Bypassing the login form in uriSecurity filter

What can I do with filters?

Filters allow you to encapsulate recurring tasks and modularize code. Filters can also transform a response from a servlet page. A common task is to format data sent back to the client, such as sending XML instead of HTML.

Some functions filters can perform:

  • Authentication based on user identity

  • Logging, auditing, tracking, personalization

  • Image conversion, scaling maps

  • Data compression

  • Localization

Customization example

Incoming requests to display a page are handled by the filter chain, which is the place to start if you want to add your own business logic to Magnolia.

A typical use case is connecting to a new framework with Magnolia. This is generally accomplished by implementing the following steps:

  1. Read the request and decide if the framework should handle it.

  2. Implement a filter to do this task.

  3. Place the filter in the proper order in the filter chain.

    You can save the resulting model to be rendered as an attribute of the request’s MgnlContext object as follows:

    MgnlContext.setAttribute("xyModel", customModel)
  4. Access the model in your rendering system using freemarker like this:

[#assign customModel = ctx.xyModel]

Extension points

These points are where you can extend Magnolia request handling with additional custom business logic:

Area Object Interface/parent class Definition Remarks

Filter chain

Filter

info.magnolia.cms.filters.AbstractMgnlFilter

In the config workspace at /server/filters

The filters in the filter chain are executed in the configured order in the repository. Objects you store as attributes of the request’s MgnlContext object can be fetched via FreeMarker later on.

See also Custom filters.

Template

Renderer

info.magnolia.rendering.renderer.AbstractRenderer

Define a renderer with a new type in a module’s template-renderers section.

Use this new type in the template’s renderType property.

Component

Renderer

info.magnolia.rendering.renderer.AbstractRenderer

Define a renderer with a new type in a module’s paragraphs-renderers section.

Use this new type in the component’s renderType property.

Feedback

DX Core

×

Location

This widget lets you know where you are on the docs site.

You are currently perusing through the DX Core docs.

Main doc sections

DX Core Headless PaaS Legacy Cloud Incubator modules