Search This Blog

Sunday 15 November 2015

Servlet 3.x - time to have a look

Its not brand new - in fact it first appeared in December 2009. Since starting to use servlets (actually servlet 2.5) I never really bothered to look at the specs. What started with application development using MVC and having multiple servlets changed to Spring framework with a single controller and lot of JSPs and then less JSPs and more AJAX. Along the way, my web.xml changed to refer to 3.0 and then 3.1.
I even used certain features without really exploring the specs. So now when the world moves towards newer and more powered client side technologies like Angular and mobile development and HTML 5, I decided to take a pause and look at the Servlet specs.
Servlet 3.0 specs came to be in 2009. As of today - 2015, we have Servlets 3.1. I decided to go over and check out the new features in these specs.
The first one I decide to try was the web-fragment feature.
In the Pre Servlet 3.0 days, the web.xml was the single point for all servlets, filters and other web.xml definitions. So if you were using a framework say something like SpringMVC, than you needed to update the web.xml of your project with definitions for the Spring Front Controller. So if the frameworks like Spring MVC, Spring Security, Struts etc start providing jars with appropriate fragments, then we can directly include them in the war and execute the code.
Consider the filter I created here:
public class SimpleFilter implements Filter {

  @Override
  public void init(FilterConfig arg0) throws ServletException {
    System.out.println("SimpleFilter initialized");
  }

  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
      throws IOException, ServletException {
    String requestUrl = ((HttpServletRequest) servletRequest).getRequestURL().toString();
    System.out.println("url trapped in SimpleFilter " + requestUrl);
    filterChain.doFilter(servletRequest, servletResponse);
    return;

  }

  @Override
  public void destroy() {
    System.out.println("SimpleFilter destroyed");
  }
}
The definition for the filter was placed in a separate XML file:
<?xml version="1.0" encoding="UTF-8"?>
<web-fragment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 xmlns:webfragment="http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
  http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd"
 id="SimpleFilterWebFragment" version="3.0">
 
 <filter>
  <filter-name>SimpleFilter</filter-name>
  <filter-class>com.simple.SimpleFilter</filter-class>
 </filter>
 
 <filter-mapping>
  <filter-name>SimpleFilter</filter-name>
  <url-pattern>*.jsp</url-pattern>
 </filter-mapping>
 
</web-fragment>
As seen here we have a root level xml-fragment element which holds the details of the filter. The web-fragment element is in fact is near identical to the web-app element.
The next step is to bundle it into a jar:
The jar structure

The next step is to add the jar to a web application.

Within the web application I placed a similar filter:
public class LocalFilter implements Filter {

  @Override
  public void init(FilterConfig arg0) throws ServletException {
    System.out.println("LocalFilter initialized");
  }

  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 
      FilterChain filterChain) throws IOException, ServletException {
    String requestUrl = ((HttpServletRequest) servletRequest).getRequestURL().toString();
    System.out.println("url trapped in LocalFilter " + requestUrl);
    filterChain.doFilter(servletRequest, servletResponse);
    return;

  }

  @Override
  public void destroy() {
    System.out.println("LocalFilter destroyed");
  }
}
Thus the application has two filters:
  1. SimpleFilter - This filter is placed within the jar and loads based on the web-fragment.
  2. LocalFilter - This filter is defined in the web app and loads based on the web.xml
If we start the server:
LocalFilter initialized
SimpleFilter initialized
INFO: Server startup in 1076 ms
As seen here first the LocalFilter instance defined in web.xml was loaded and read. The Servlet Container than scanned the jars in the project looking for any web-fragments. It detected and loaded the SimpleFilter instance. On sending a request for index.jsp
url trapped in LocalFilter http://localhost:8080/WebFragments/index.jsp
url trapped in SimpleFilter http://localhost:8080/WebFragments/index.jsp
What if we need this sequence changed ? The Oracle blogs has a good entry which discusses on the ordering behavior. It talks about the absolute-ordering element used in web.xml and ordering element in the fragment file.
In the next post I shall look at other new features.

1 comment: