API,  Java,  Servlets

Java Servlet API

The Servlet API is an important feature in building Java web applications. Servlets run in a servlet container which is a web or application server that provides network services for receiving requests and sending responses.

All Java EE application servers support the servlet specification and contains a servlet container where servlets can be initialized.

Once a servlet is initialized, it is available to process HTTP requests sent from a web browser using a servlet interface method that corresponds to the HTTP method of the request. Dynamic content is then generated in a response that is sent back to the browser. The servlet manages functionality required to interact with a database or generate dynamic HTML content for example.

Java EE Servlet API concept overview

The servlet interface contains methods that can be implemented for processing requests related to HTTP methods eg. POST, GET, PUT, DELETE, etc. as well as providing access to the HTTP message for the creation of headers, cookies and body content.

Example of HTTP Message

Servlets are configured in the application with annotations from Java EE version 7, although XML based configuration could be used in previous versions.

For detailed information of the HTTPServlet interface, documentation can be viewed here.

Asynchronous processing is supported to enable the servlet container to process resources more efficiently by releasing threads during long running processes.

The servlet API provides an abstraction over low-level interfaces for networking and request parsing.

@WebServlet("/ExampleServlet")
public class ExampleServlet extends HttpServlet {
   
  protected void DoGet(HttpServletRequest request, HttpServletResponse response)
     throws ServletException, IOException {
     response.getWriter().append("Hello Naiomi");
  }

  protected void DoPost(HttpServletRequest request, HttpServletResponse response)
     throws ServletException, IOException {
     doGet(request, response);
  }
}

Additional interfaces

InterfaceDescription
HttpSessionAllows state to be stored for a user across one or more HTTP requests by a user
CookieObject to send a small amount of information to the browser that will be sent back at a later time
ServletContextProvides methods to communicate with the servlet container
FilterProvides tasks on a request to a servlet or on the response from a servlet

Filters

Filters can be used with a Servlet to enable some logic or transformations to be applied to requests and responses processed by a Java application. Common use cases include logging or security applied to the requests received and the response sent.

//Servlet Filter implementation for Logging

@WebFilter("/*")
public class LoggingFilter implements Filter {
   
   public void doFilter(ServletRequest request, ServletResponse response,  
       FilterChain chain) throws IOException, ServletException {
     
      request.getParameterMap().entrySet().stream().forEach(entry ->{
	System.out.println(String.format("%s:%s", entry.getKey(), entry.getValue()[0]));
      });
      
      chain.doFilter(request, response);
   }
}

Event Listeners

A Listener is an interface that receives notifications about events occurring in the web application and is used to handle events such as:

  • Application events at app start/end
  • Session events at Session start/end
  • Request events at Request start/end
  • Attribute events when attribute is added/removed

The listener is notified when the event occurs and can perform an action in response to the event.

Listener interfaces
Simple context listener
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;

public class SimpleListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        sce.getServletContext().log("Application started");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        sce.getServletContext().log("Application now ended");
    }
}

If you choose to use the web.xml to register the listener instead of using the @WebListener annotation:

<listener>
   <listener-class>com.listeners.SimpleListener</listener-class>
</listener>
Simple request listener
import jakarta.servlet.ServletRequestEvent;
import jakarta.servlet.ServletRequestListener;
import jakarta.servlet.annotation.WebListener;

@WebListener
public class SimpleRequestListener implements ServletRequestListener {

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        sre.getServletContext().log(String.format("Application called from %s", sre.getServletRequest().getRemoteAddr()));
    }

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        sre.getServletContext().log(String.format("Application call ended from %s", sre.getServletRequest().getRemoteAddr()));
    }
}

Asynchronous support

Servlets can often be expensive when events such as remote web service requests or CRUD operations on the database are required. When these operations occur frequently, the web application server can experience poor performance due to thread starvation. Threads are valuable resources for web containers so it’s important to use them efficiently.

Asynchronous support, introduced from Java EE 7 assist with efficient thread utilization.

//Implementing async support on a Servlet

@WebServlet(urlPatterns= "/ExampleServlet", asyncSupported = true)
public class ExampleServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public CatalogServlet() {
		super();
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
           throws ServletException, IOException {
		response.getWriter().append(request.getParameter("name"));
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
	
		AsyncContext asyncContext = request.startAsync();
		
		asyncContext.start(new Runnable() {

		@Override
		public void run() {
				
		   try {
			Thread.sleep(5000);
			System.out.println("Print the response");
			System.out.println("Reponse returned by: " + Thread.currentThread().getName());
			returnResponse(request, response);
			asyncContext.complete();

		   } catch (InterruptedException e) {
			e.printStackTrace();
		     } catch (IOException e) {
			 e.printStackTrace();
		       }
				
		  }
			
	        });
		
		System.out.println("Initial Request: " + Thread.currentThread().getName());
		
	}

	private void returnResponse(HttpServletRequest request, HttpServletResponse response) throws IOException {
		...
	}
	
	

Leave a Reply

Your email address will not be published. Required fields are marked *