Using Portlet Filters

Portlet filters intercept requests and responses at the start of each portlet request processing phase so you can add functionality there. This makes them useful for auditing portlet activities, transforming content, adding or modifying request and response attributes, suspending portlet phases to get user inputs, and more.

Follow these steps to create portlet filters:

  1. Identify the target portlet by its full name (e.g., com_liferay_blogs_web_portlet_BlogsPortlet).

  2. Determine the portlet phase you want to intercept and implement the corresponding portlet filter interface from the javax.portlet.filter package.

    See Portlets for more information about each portlet phase.

  3. Declare the portlet filter a Component within the OSGi framework using the @Component annotation and identify it as a PortletFilter.class service.

    Note

    Portlet filters are OSGi Declarative Service (DS) Components. Filters can also be applied to a portlet using a portlet.xml descriptor or a @PortletLifecycleFilter annotation.

  4. Enter the following properties into the @Component declaration.

    • "javax.portlet.name=[portlet_name]": This property sets the filter’s target portlet.
    • "service.ranking:Integer=[priority]": This property sets the filter’s ranking, with the higher integers executing first. Ensure the filter starts at the beginning of the filter chain by assigning it the highest ranking.
  5. Override the filter’s doFilter method to add the desired functionality.

The following example uses a RenderFilter to audit the render phase for the Blogs portlet.

Deploying the Sample Portlet Filter

Start a new Liferay instance by running

docker run -it -m 8g -p 8080:8080 liferay/portal:7.4.3.120-ga120

Sign in to Liferay at http://localhost:8080. Use the email address test@liferay.com and the password test. When prompted, change the password to learn.

Then, follow these steps to download, build, and deploy the sample Portlet Filter to the new docker container:

  1. Download and unzip the example module.

    curl https://resources.learn.liferay.com/dxp/latest/en/liferay-development/liferay-internals/extending-liferay/liferay-b4k8.zip -O
    
    unzip liferay-b4k8.zip
    
  2. Run the following gradlew command to build the JAR file and deploy it to your new Docker container:

    cd liferay-b4k8
    
    ./gradlew deploy -Ddeploy.docker.container.id=$(docker ps -lq)
    

    The JAR is generated in the build/libs folder (i.e., b4k8-impl/build/libs/com.acme.b4k8.impl-1.0.0.jar).

  3. Confirm the module was successfully deployed and started via the container console.

    Processing com.acme.b4k8.impl-1.0.0.jar
    STARTED com.acme.b4k8.impl_1.0.0 [1656]
    
  4. Verify the portlet filter is working by adding the Blogs widget to a site page.

    Whenever a render request is made to the Blogs portlet, the container console shows a warning message with an audit of its render time, average render time, and total number of renders.

    WARN [http-nio-8080-exec-2][B4K8PortletFilter:54] Blogs portlet rendered in 3 ms with an average of 3 ms out of 1 renders.
    WARN [http-nio-8080-exec-10][B4K8PortletFilter:54] Blogs portlet rendered in 0 ms with an average of 1 ms out of 2 renders.
    

Auditing a Portlet’s Render Phase with a Portlet Filter

The provided sample filter targets the Blogs portlet and audits its render phase using the RenderFilter interface.

@Component(
	property = {
		"javax.portlet.name=com_liferay_blogs_web_portlet_BlogsPortlet",
		"service.ranking:Integer=100"
	},
	service = PortletFilter.class
)
public class B4K8PortletFilter implements RenderFilter {

	@Override
	public void destroy() {
	}

	@Override
	public void doFilter(
			RenderRequest renderRequest, RenderResponse renderResponse,
			FilterChain filterChain)
		throws IOException, PortletException {

		long startTime = System.currentTimeMillis();

		filterChain.doFilter(renderRequest, renderResponse);

		long renderTime = (System.currentTimeMillis() - startTime) / 1000;

		_totalTime.add(renderTime);

		_count.increment();

		if (_log.isInfoEnabled()) {
			long count = _count.longValue();

			long averageRenderTime = _totalTime.longValue() / count;

			_log.info(
				"Blogs portlet rendered in " + renderTime +
					" ms with an average of " + averageRenderTime +
						" ms out of " + count + " renders.");
		}
	}

	@Override
	public void init(FilterConfig filterConfig) throws PortletException {
	}

	private static final Log _log = LogFactoryUtil.getLog(
		B4K8PortletFilter.class);

	private final LongAdder _count = new LongAdder();
	private final LongAdder _totalTime = new LongAdder();

}

In this code, the filter is first declared an OSGi DS Component and identified as a PortletFilter.class service. As part of this declaration, it also sets two properties: the first property targets the BlogsPortlet, and the second property sets its priority to 100.

The portlet filter proceeds to implement the RenderFilter interface, which extends the PortletFilter interface. This interface includes three methods (i.e., init, destroy, doFilter) and performs its filtering tasks on both the render request to the Blogs portlet and its response.

  • init: Called when the portlet filter is first deployed to Liferay and initialized within the portlet container.

  • destroy: Called to remove the portlet filter from service.

  • doFilter: Called by the portlet container each time a render request/response pair is passed through the chain due to a client request.

In this example, doFilter audits the Blogs portlet in the following ways:

  1. Notes the render phase start time.

    long startTime = System.currentTimeMillis();
    
  2. Executes the doFilter method for the FilterChain to invoke every RenderFilter in the chain.

    filterChain.doFilter(renderRequest, renderResponse);
    
  3. Calculates the time it takes for the Blogs portlet to complete the render phase.

    long renderTime = (System.currentTimeMillis() - startTime) / 1000;
    
  4. Adds the current render time to the total time of all renders.

    _totalTime.add(renderTime);
    
  5. Increments the total number of portlet renders.

    _count.increment();
    
  6. Uses the LongAdder utility to store the portlet’s average render time and total number of renders, and then uses the Log utility to display these values along with the portlet’s current render time.

if (_log.isInfoEnabled()) {
	long count = _count.longValue();

	long averageRenderTime = _totalTime.longValue() / count;

	_log.info(
		"Blogs portlet rendered in " + renderTime +
			" ms with an average of " + averageRenderTime +
				" ms out of " + count + " renders.");
}

Whenever a render request is made, this doFilter is called.

Capabilities

Product

Contact Us

Connect

Powered by Liferay
© 2024 Liferay Inc. All Rights Reserved • Privacy Policy