August 9, 2012

Servlet 3.0 Web Fragments and other Features

This article covers a very exciting feature of Servlets 3.0 and that is support for Web Fragments. The Java Servlets have come up with lots of cool features to bring up Ease of Development, Plug-ability and Asynchronous Request Processing. In this article we will have a detailed discussion on Web Fragments with examples, but to start with, lets have a brief overview of other features of Servlets 3.0.

 

New Annotations:

Servlets 3.0 have come up with a set of new Annotations for the declarations of Request Mappings, Init-Params, Listeners, and Filters that makes the use of Deployment Descriptor (web.xml) absolutely optional. We can still keep the deployment descriptor and override the existing mappings, and other configurations. The Annotation based configurations makes the code more readable and also saves us from maintaining nasty and cumbersome deployment descriptors. Lets have quick look at these annotations.

1. @MultipartConfig: The new Servlets have inbuilt support for File Upload. Having this annotation on the top of a servlet indicates that the Request that the servlet is expecting will have multipart/form-data MIME data. This annotation can also specify location to store the file on server, maxFileSize allowed for uploaded files, maxRequestSize allowed for multipart/form-data requets, and fileSizeThreshold after exceeding it the file content will be written on the disk.


2. @WebListener: Classes annotated withe WebListeners are treated as Listeners by the containers. The class still needs to extend the appropriate listener class. The container, by making use of reflections, will identify the type of Listener.
      @WebListener
       public class MyListener extends ServletContextListener


3. @WebInitParam: As the name suggests this annotation supplies init param name and value pair to the servlets its declared to. Previously we used to specify the init-param in Servlet tag of the deployment descriptor.
        
      @WebInitParam(name="param1", value="foo")


4. @WebFilter: Should be used with the filter implementation classes in you application.
      @WebFilter(filterName="myFilter", urlPattern={"/foo/*", "/bar/*"})
      public class MyFilter extends Filter {


5. @WebServlet: Finally, the most important annotation of the Servlets 3.0 is Web Servlets. You annotate your servlet implementation with this annotation and the container will be able to recognize this as a servlet at the loading time. With this annotation you can specify servlet-name, url-mapping for your servlet.
      
      @WebServlet(
  asyncSupported = false, 
  name = "HelloAnnotationServlet", 
  urlPatterns = { "/helloanno" }, 
  initParams = {
    @WebInitParam(name = "param1", value = "value1"),
    @WebInitParam(name = "param2", value = "value2") 
  }
      )
      public class HelloAnnotationServlet extends HttpServlet {



File Upload:

The servlet ancestors did not have ability to Upload a file. We had to use many third party open source tools to achieve that. But the 3.o servlets has a in-built support for file uploads. Now the container is able to parse the Multipart request and make the MIME types available to the servlets through Request objects. Below are the new methods on HttpServletRequest object which helps to read Multipart requests.
       public Collection<Part> getParts();
       public Part getParts (String name);



Asynchronous Support:

This is another exciting feature of Servlets 3.0, it provides with ability to implement Comet based applications. It provides us with AsyncContext which can be started with HttpServletRequest and HttpServletResponse objects.


Web Fragments:

From a long time we have been using many MVC or Web Frameworks (e.g. Spring, Struts etc.) which work on the top of servlets. Almost all of such frameworks come along with a default Request Processor and/or a Controller. When we want to plug that framework in our application we have to add framework libraries to our project and also update our deployment descriptor to divert specific (or all of the ) requests to the default handler provided by the framework. Updating the deployment descriptor is an overhead for the developer as he has to know the default Processor, Listeners and Filters of the framework. Also if an application is using multiple frameworks together then the developer has to take extreme care while mapping correct request to the correct framework component. Web Fragments can save developers from such extra overheads.

Applications can be broken down into various modules, now the web fragments allows us to modularize the deployment descriptors as well. Gone are the days when we used to write and maintain very large web.xml file. Now, we can create modules in the application and divide the large web.xml into parts dedicated for each module.

This interesting feature helps us to divide an application Java resources into modules; package them into separate JARs and include these archives into the main application. Each module can have its own deployment descriptor (called as fragment) contained within the META-INF folder of the JAR.

When the application is deployed, the server also scans JARs under the META-INF directory and looks for web.xml fragments. If found, it will load the configurations. Below are the benefits of having Web Fragments.

1. The application level deployment descriptor, which is already optional, becomes very small in size  and easier to maintain.
2. Modularize the application structure as the module resources and the respective configurations are encapsulated together.
3. Decouples the main application from the modules that are used along with.
4. Now, the module is will decide which kind of requests it supports and what are the configurations required.
5. Frameworks like Struts and Spring can have there own xml fragment contained within their respective JAR which saves developer form making entries into the Web.xml. Also these frameworks can be easily plugged-in and out without disturbing the main application.


Before we try our own web fragment example lets have quick overview of the rules/restrictions for it.

1. We don't need to change/edit the original web.xml.
2. Any number of web fragments can be created but the file name should be web-fragment.xml.
3. The root element of web fragment should be <web-fragment>.
4. Finally, the web fragment must be present in META-INF folder of a JAR or WEB-INF in case of a WAR.

Now, lets try an example with Web Fragments.

1. Create a Web Fragment Project and add a Servlet and Web Fragment entry as described below.
MyServlet.java

public class MyServlet extends HttpServlet {
 private static final long serialVersionUID = 1L;

 protected void doGet(HttpServletRequest request,
   HttpServletResponse response) throws ServletException {
  PrintWriter writer = null;
  try {
   writer = response.getWriter();
   writer.print("");
   writer.print("");
   writer.print("This response is generated from the Plugged-in servlet");
   writer.print("");
   writer.print("");
   writer.flush();
  } catch (IOException e) {
   System.out.println("IO Exception");
  } finally {
   if (writer != null) {
    writer.close();
   }
  }
 }
}


META-INF/web-fragment.xml

<?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="WebFragment_ID" version="3.0">
 <display-name>mye</display-name>
 <name>mye</name>
 <servlet>
  <servlet-name>myServlet</servlet-name>
  <servlet-class>com.MyServlet</servlet-class>
 </servlet>
</web-fragment>



2. Now create a JAR file out of this project lets say WebFragment.jar.
3. Create another web project MyMainProject and add the webFragment.jar into the lib 4. Just add the Servlet Mapping tag into the web.xml file.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app 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"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
  http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
 id="WebApp_ID" version="3.0">
 <display-name>WebFragmentSample</display-name>
 <servlet-mapping>
  <servlet-name>myServlet</servlet-name>
  <url-pattern>/MyServlet</url-pattern>
 </servlet-mapping>
</web-app>
5. Now just run the application on any Servlet 3.0 compatible server (My one is apache-tomcat-7.0.23) and fire the below url.
http://:/MyMainProject/MyServlet.

6. You should see the below output.
This response is generated from the Plugged-in servlet