How to use Jakarta Servlet Filters and Listeners

Here in this article we will try to build a very basic servlet based application and see how we can use the filters and listeners features.
Test Environment
- OpenJDK 17.0.13
- Eclipse GlassFish 7.0.20
- Apache Maven 3.9.1
- VSCode Editor 1.97.2
What are Jakarta Servlet Filters
A filter is an object that can transform the header and content (or both) of a request or response. Filters differ from web components in that filters usually do not themselves create a response. We can map these filters to web components based on the url pattern to manage their request and response objects.
What are Jakarta Servlet listeners
Servlet listeners are classes that implement predefined interfaces that define methods to handle different types of servlet events occurring within a web application’s lifecycle, such as context initialization/destruction, request scoping, and session management.
High Level Architecture

If you are interested in watching the video. Here is the YouTube video on the same step by step procedure outlined below.
Procedure
Step1: Ensure the following Pre-requisite installed
Ensure that you have JDK, Maven and Glassfish Enterprise application server installed on your workstation.
admin@fedser:~$ javac --version
javac 17.0.13
admin@fedser:~$ mvn --version
Apache Maven 3.9.1 (Red Hat 3.9.1-3)
Download and install the Glassfish Enterprise Application server. Also ensure that your PATH variable is set to the bin directory of the glassfish application server.
admin@fedser:~$ export PATH=$PATH:/home/admin/middleware/stack/glassfish7/bin
Update your glassfish server adminconsole user “admin” password by editing the following file.
admin@fedser:~$ cat /home/admin/middleware/stack/glassfish7/glassfish/domains/password.properties
#AS_ADMIN_PASSWORD=adminadmin
AS_ADMIN_PASSWORD=admin@1234
Ensure that the Glassfish application server is up and running.
admin@fedser:~$ asadmin start-domain
Waiting for domain1 to start .........
Waiting finished after 8,101 ms.
Successfully started the domain : domain1
domain Location: /home/admin/middleware/stack/glassfish7/glassfish/domains/domain1
Log File: /home/admin/middleware/stack/glassfish7/glassfish/domains/domain1/logs/server.log
Admin Port: 4,848
Command start-domain executed successfully.
Validate if you able to access the Admin Console page for the Glassfish Server.
URL - http://localhost:4848/common/index.jsf
Step2: Create a maven jakartaee minimal project
Here we will create a maven archetype project using the CLI with the below mentioned options to generate a minimal jakartaee version 10 project.
admin@fedser:vscodeprojects$ mvn archetype:generate -DarchetypeArtifactId="jakartaee10-minimal" -DarchetypeGroupId="org.eclipse.starter" -DarchetypeVersion="1.1.0" -DgroupId="com.stack" -DartifactId="servletadvdemo"
admin@fedser:vscodeprojects$ cd servletadvdemo/
admin@fedser:servletadvdemo$ rm -rf src/main/java/com/stack/servletadvdemo/*
admin@fedser:servletadvdemo$ rm -rf src/main/resources/*
Step3: Create ThemeServlet.java
Here we are going to create our servlet named “ThemeServlet”. This servlet generates a HTML response when a request is recieved on “/welcome”.
The important thing to note about this servlet is the “theme” attribute. We are using this “theme” attribute value to update the background color of the response that we are sending to end user. This attribute is going to introuced into our request using filters in servlet which we will look in the upcoming steps.
admin@fedser:servletadvdemo$ cat src/main/java/com/stack/servletadvdemo/ThemeServlet.java
package com.stack.servletadvdemo;
import java.io.IOException;
import java.io.PrintWriter;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@WebServlet("/welcome")
public class ThemeServlet extends HttpServlet {
private static final long serialVersionUID = 18925377774889413L;
protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
out.println("<html lang=\"en\">");
out.println("<head>");
out.println("<title>Welcome Page</title>");
out.println("</head>");
String theme = (String) request.getAttribute("theme");
out.println("<body style='background-color:" + theme + ";'>");
out.println("<h1>Servlet ThemeServlet at " + request.getContextPath() + "</h1>");
out.println("<h2>Hello, The Background color theme HEX code is: " + theme + "</h2>");
out.println("</body>");
out.println("</html>");
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
processRequest(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
public String getServletInfo() {
return "ThemeServlet";
}
}
Step4: Create ThemeFilter.java
Here we are going to create a filter class named “ThemeFilter.java” by annotating it with @WebFilter annotation and providing a name to our filter. We are also providing the urlPatterns which helps to identify all the resources for which this filter is applicable. Also we are passing “@WebInitParam” paramter for the attribute “theme” for which the default value would be “#FF1493”.
This class uses java utility classes to identify the Hour of the day and based on that it assigns a value to the “theme” variable. This variable is used to set request attribute and modified request and the response objects are passed to the “chain.doFilter” method. This causes the next filter in the chain to be invoked, or if the calling filter is the last filter in the chain, causes the resource at the end of the chain to be invoked.
In addition to doFilter, we must implement the init and destroy methods which are self explainatory.
admin@fedser:servletadvdemo$ cat src/main/java/com/stack/servletadvdemo/ThemeFilter.java
package com.stack.servletadvdemo;
import java.io.IOException;
import java.util.Calendar;
import java.util.GregorianCalendar;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.annotation.WebInitParam;
@WebFilter(filterName = "ThemeFilter",
urlPatterns = {"/*"},
initParams = {
@WebInitParam(name = "theme", value = "#FF1493")})
public class ThemeFilter implements Filter {
String theme = null;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
theme = filterConfig.getInitParameter("theme");
}
@Override
public void doFilter(ServletRequest req,
ServletResponse res,
FilterChain chain) throws IOException, ServletException {
Calendar cal = GregorianCalendar.getInstance();
switch (cal.get(Calendar.HOUR_OF_DAY)) {
case 1: case 2: case 3: case 4: case 5: case 6: theme="#7FFFD4"; break;
case 7: case 8: case 9: case 10: case 11: case 12: theme="#F5F5DC"; break;
case 13: case 14: case 15: case 16: case 17: case 18: theme="#DB7093"; break;
case 19: case 20: case 21: case 22: case 23: case 25: theme="#9400D3"; break;
default : theme="#9400D3";
}
req.setAttribute("theme", theme);
chain.doFilter(req, res);
}
@Override
public void destroy() {
}
}
Step5: Create ThemeServletListener.java
Here we are going to create a listener class named “ThemeServletListener.java”. We can monitor and react to events in a servlet’s lifecycle by defining listener objects whose methods get invoked when lifecycle events occur. A listener class needs to be annotated with “@WebListener()” and it mush implement the listner interfaces as shown below.
When a listener method is invoked, it is passed an event that contains information appropriate to the event.
admin@fedser:servletadvdemo$ cat src/main/java/com/stack/servletadvdemo/ThemeServletListener.java
package com.stack.servletadvdemo;
import java.util.logging.Level;
import java.util.logging.Logger;
import jakarta.servlet.ServletContextAttributeEvent;
import jakarta.servlet.ServletContextAttributeListener;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.annotation.WebListener;
@WebListener()
public class ThemeServletListener implements ServletContextListener, ServletContextAttributeListener{
static final Logger log = Logger.getLogger("com.stack.ThemeServletListener");
@Override
public void contextInitialized(ServletContextEvent sce) {
log.info("Context initialized");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
log.info("Context destroyed");
}
@Override
public void attributeAdded(ServletContextAttributeEvent event) {
log.log(Level.INFO, "Attribute {0} has been added, with value: {1}",
new Object[]{event.getName(), event.getValue()});
}
@Override
public void attributeRemoved(ServletContextAttributeEvent event) {
log.log(Level.INFO, "Attribute {0} has been removed",
event.getName());
}
@Override
public void attributeReplaced(ServletContextAttributeEvent event) {
log.log(Level.INFO, "Attribute {0} has been replaced, with value: {1}",
new Object[]{event.getName(), event.getValue()});
}
}
Step6: Update pom.xml to deploy to Glassfish server
Here we are updating the pom.xml “properties” section to add “glassfish.home” directory where the glassfish server is installed. Also we are updating the plugins section with “org.codehaus.cargo” plugin to carry out automated deployment using the mvn cli to the glassfish server based on configuration properties that are provided. If you are not using this plugin you can generate the war package and deploy it manually to your glassfish server.
admin@fedser:servletadvdemo$ cat pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.stack</groupId>
<artifactId>servletadvdemo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>servletadvdemo</name>
<properties>
<maven.compiler.release>17</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<glassfish.home>/home/admin/middleware/stack/glassfish7</glassfish.home>
</properties>
<dependencies>
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>10.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>servletadvdemo</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven3-plugin</artifactId>
<version>1.10.6</version>
<executions>
<execution>
<id>deploy</id>
<phase>integration-test</phase>
<goals>
<goal>redeploy</goal>
</goals>
</execution>
</executions>
<configuration>
<container>
<containerId>glassfish7x</containerId>
<type>installed</type>
<home>${glassfish.home}</home>
</container>
<configuration>
<type>existing</type>
<home>${glassfish.home}/glassfish/domains</home>
<properties>
<cargo.glassfish.domain.name>domain1</cargo.glassfish.domain.name>
</properties>
</configuration>
</configuration>
</plugin>
</plugins>
</build>
</project>
Step7: Build and Deploy Application
Now it’s time to build, package and deploy the application to glassfish application server as shown below.
admin@fedser:servletadvdemo$ mvn clean package cargo:deploy
Step8: Validate Application
Let us now validate our application by calling the below url.
URL: http://localhost:8080/servletadvdemo/welcome

Also you validate you glassfish application server logs to check events logged under “ThemeServletListener” as shown below.
[2025-03-11T08:48:12.253370+02:00] [GF 7.0.20] [INFO] [] [com.stack.ThemeServletListener] [tid: _ThreadID=59 _ThreadName=admin-listener(4)] [levelValue: 800] [[
Attribute org.glassfish.jsp.isStandaloneWebapp has been added, with value: true]]
[2025-03-11T08:48:12.265211+02:00] [GF 7.0.20] [INFO] [] [com.stack.ThemeServletListener] [tid: _ThreadID=59 _ThreadName=admin-listener(4)] [levelValue: 800] [[
Context initialized]]
Hope you enjoyed reading this article. Thank you..
Leave a Reply
You must be logged in to post a comment.