part from the addition of functionalities such as filters and web application events, the Servlet specification?one of the key Java APIs for web application development?has not undergone any major changes since its introduction. However, the specification has remained robust, and the release of the new Servlet 3.0 specification (JSR 315) will affect a major change in the way developers build Java web applications.
This article offers a brief overview to the new features in Servlet 3.0. Then, using code samples, it dives into the details of using annotations for Servlet 3.0 filters and listeners. The discussion also touches on how to plug frameworks and other libraries into a web application using web fragments. The article concludes with a brief discussion of Servlet 3.0’s support for asynchronous processing and highlights of the enhancements made to the existing APIs.
The New Features in Servlet 3.0: An Overview
The Servlet 3.0 specification has three goals for the developers who employ it:
- Simplicity
- Ease of development
- Adherence to Web 2.0 principles
To make the development process easier, Servlet 3.0 introduces annotations. Similar to the changes in EJB 3.1, the introduction of annotations makes the web deployment descriptor –web.xml optional.
Pluggability
Whenever you use a third-party framework such as Struts, JSF, or Spring, you need to have a corresponding entry for the respective Servlet in web.xml. This requirement makes the web deployment descriptor cumbersome and difficult to maintain. Enter the new pluggability feature in Servlet 3.0, which makes web applications modular and easier to maintain. Implemented through web fragments, pluggability relieves the developer from making too many Servlet configuration entries in the web.xml file.
Asynchronous Processing
Another significant change in the new Servlet specification is the support for asynchronous processing, a useful feature for AJAX applications. When a Servlet creates a thread to make a request, it often has to wait for a response from a resource like a database or message connection before it can perform another operation on that thread. Asynchronous processing avoids such blocking requests by allowing the thread to perform some other operation.
Apart from the features mentioned here, several other enhancements have been made to the existing API. The sections towards the end of the article will explore these features one by one in detail.
Author’s Note: To run a Servlet developed with Servlet 3.0, your Servlet container should run Java SE 6 and above. |
Annotations in Servlet
One of the major changes in Servlet 3.0 is the support for annotations. Using annotations to define Servlets and filters eliminates the need for the Servlet/Filter entry in the web deployment descriptor (web.xml).
@WebServlet
To define a Servlet component in a web application, you use @WebServlet. You use it on a class that extends the javax.servlet.http.HttpServlet class. The @WebServlet annotation has many attributes, such as name, urlPatterns, and initParams, which you use to define the Servlet’s behavior. For the url pattern, you must specify it either with the annotation itself or with an attribute of the annotation.
You can define a simple Servlet with @WebServlet as follows:
@WebServlet(name = "GetQuoteServlet", urlPatterns = {"/getquote"} )public class GetQuoteServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); try { String symbol = request.getParameter("symbol"); out.println("Stock Price is
" + StockQuoteBean.getPrice(symbol); } finally { out.close(); } }}public class StockQuoteBean {private StockQuoteServiceEntity serviceEntity = new StockQuoteServiceEntity(); public double getPrice(String symbol) { if(symbol !=null ) {return serviceEntity.getPrice(symbol); } else { return 0.0; } }}
You can modify the same Servlet to address requests from multiple URLs with the annotation attributes.
@WebServlet(name = "GetQuoteServlet", urlPatterns = {"/getquote", "/stockquote"} )public class GetQuoteServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); try { String symbol = request.getParameter("symbol"); out.println("Stock Price is
" + StockQuoteBean.getPrice(symbol); } finally { out.close(); } }}
@WebFilter
You use the @WebFilter annotation to define a filter. This annotation also has optional parameters. You can use @WebFilter on any class that implements the javax.servlet.Filter interface. Similar to the @WebServlet annotation, you must specify the url pattern on this annotation as well.
@WebFilter(filterName = "AuthenticateFilter", urlPatterns = {"/stock.jsp", "/getquote"})public class AuthenticateFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String username = ((HttpServletRequest) request).getParameter("uname"); String password = ((HttpServletRequest) request).getParameter("password"); if (username == null || password == null) { ((HttpServletResponse) response).sendRedirect("index.jsp"); } if (username.equals("admin") && password.equals("admin")) { chain.doFilter(request, response); } else { ((HttpServletResponse) response).sendRedirect("index.jsp"); } } public void destroy() { } public void init(FilterConfig filterConfig) { }}
@WebInitParam
You use the @WebInitParam annotation to specify the init parameters to the Servlet or filter. Alternatively, you can specify the init parameters with the initParam attributes of the @WebServlet and @WebFilter annotations.
@WebServlet(name = "GetQuoteServlet", urlPatterns = {"/getquote"})@WebInitParam(name = "default_market", value = "NASDAQ")public class GetQuoteServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { String market = getInitParameter("default_market"); String symbol = request.getParameter("symbol"); out.println("Stock Price in " + market + " is
" + StockQuoteBean.getPrice(symbol, market)); } finally { out.close(); } }}
Here is an alternate example that uses the @WebInitParam annotation as part of the @WebServlet and @WebFilter initParams attribute:
@WebServlet(name = "GetQuoteServlet", urlPatterns = {"/getquote"}, initParams={@WebInitParam(name="default_market", value="NASDAQ")} )public class GetQuoteServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); try { String market = getInitParameter("default_market"); String symbol = request.getParameter("symbol"); out.println("Stock Price in " + market + " is
" + StockQuoteBean.getPrice(symbol, market)); } finally { out.close(); } }}
@WebListener
You use the @WebListener annotation on a class that acts as a listener to various web application events in a given web application context. You can use @WebListener to annotate a class that implements ServletContextListener, ServletContextAttributeListener, ServletRequestListener, ServletRequestAttributeListener, HttpSessionListener, and HttpSessionAttributeListener. Here is an example with ServletContextListener:
@WebListenerpublic class QuoteServletContextListener implements ServletContextListener { public void contextInitialized(ServletContextEvent sce) { ServletContext context = sce.getServletContext();context.setInitParameter(“default_market”, “NASDAQ”);}public void contextDestroyed(ServletContextEvent sce) {}}
@MultipartConfig
Use the @MultipartConfig annotation to specify the multipart MIME type request for the Servlet. The MIME attachments are read from the request object.
The Metadata and Common Annotations
Apart from the Servlet-specific annotations described above, Servlet 3.0 continues to support all the annotations that are defined as part of JSR 175 (Java Metadata Specification) and JSR 250 (Common Annotations for the Java Platform), including:
- Annotations related to security, such as @DeclareRoles and @RolesAllowed
- Annotations to use EJB, such as @EJB and @EJBs
- Annotations for resource injection, such as @Resource and @Resources
- Annotations to use JPA, such as @PersistenceContext, @PersistenceContexts, @PersistenceUnit, and @PersistenceUnits
- Life cycle annotations, such as @PostConstruct and @PreDestroy
- Annotations to provide references to web services, such as @WebServiceRef and @WebServiceRefs
Annotations or web.xml?
The introduction of annotations makes the web deployment descriptor (web.xml) optional when configuring web components. However, if you have to make any changes or updates to the configuration, you can still use the deployment descriptor. The container will decide to use web.xml or annotations depending on the value for the element metadata-complete in the web.xml descriptor. If the attribute has a value true, then the container does not process the annotations and web fragments; the deployment descriptor is the only source for all the metadata information. The container will process annotations and web fragments only if the element metadata-complete is not there or does not have a value true.
Pluggability Through Web Frameworks
As discussed previously, Servlet 3.0 includes enhancements to enable you to plug frameworks and libraries into a web application. This pluggability reduces the number of configurations and provides good modularity for web applications. Servlet 3.0 achieves pluggability through web module deployment descriptor fragments (or web fragments, for short).
A web fragment is a part of the web.xml file specified and included in the framework-specific JAR’s META-INF directory. A web fragment provides logical partitioning of the web application without your having to edit the web deployment descriptor for framework-specific components.
The elements (tags) used in the web fragment are almost the same set of elements (tags) used in the deployment descriptor, except the root element (parent tag). The root element for the web fragment should be web-fragment, and hence the file should be called web-fragment.xml. The container will look for web-fragment.xml only in the JAR file placed under the WEB-INFlib folder. If the JAR file under the lib directory has any web-fragment.xml files, the container will load the required classes and process them.
Just as the Servlet name is expected to be unique in a given web.xml file, the same logic applies to web fragments as well. In addition, the Servlet name must be unique in the entire web application, including the web.xml and all the web fragments.
As an example, the following web-fragment.xml is placed under the jarsMETA-INF directory of frameworks:
web-fragment.xmlControllerServlet com.app.control.ControllerServlet com.listener.AppServletContextListener
The framework JAR file is placed under the WEB-INFlib directory. The Servlet 3.0 specification does not define the ordering of configuration from web-fragment.xml and annotations, but it does define the ordering of configuration of web.xml and web-fragment.xml as follows:
- Absolute ordering
- Relative ordering
Figure 1. Absolute Ordering in Servlet 3.0: You achieve absolute ordering with the help of the |
You achieve absolute ordering with the help of the
web.xmlDemoApp WebFragment1 WebFragment2 ...
Figure 2. Relative Ordering in Servlet 3.0: You achieve relative ordering with the help of the |
You achieve relative ordering with the help of the
To understand the relative ordering better, consider some examples. The following example assumes that three JAR files each has a web-fragment.xml file.
web-fragment.xmlWebFragment1 WebFragment2 ... web-fragment.xmlWebFragment2 .. web-fragment.xmlWebFragment3 ..
The files will be processed in the following order:
- WebFragment3
- WebFragment2
- WebFragment1
The JAR file having WebFragment3 will be processed first because of the
If web.xml encounters both
Asynchronous Processing in Servlet
In many situations, a Servlet has to interact with a resource for processing data. It could be a database resource, a web service, or a message resource. While interacting with these resources, the Servlet has to wait until it gets a response from the resource before it actually generates a response. This makes the Servlet call to the resource a blocking call and results in inefficiency. Servlet 3.0 addresses this issue with the introduction of asynchronous processing. Asynchronous processing allows the thread to issue a call to the resource and return back to the container without getting blocked. The thread can perform other tasks, which makes Servlet 3.0’s performance more efficient. AsyncContext, which manages the response from the resource, decides whether the response from the resource will be handled by the same thread or dispatched to a new resource in the container. AsyncContext has methods such as start, dispatch, and complete to perform the asynchronous process.
Servlet 3.0’s asynchronous processing is supported through the asyncSupported attribute available in both @WebServlet and @WebFilter annotations. This attribute takes a Boolean value, which by default has a false value. You enable asynchronous processing in Servlet by setting a true value to this attribute in the Servlet or in the filter.
When combined with comet, Servlet asynchronous processing becomes an ideal solution for AJAX applications. In the init method of a Servlet, the thread can start any database operation or read/write a message to a queue. In the doGet or doPost method, you can start the asynchronous processing and the AsyncContext will manage the thread related to the database or message operation with the help of AsyncEvent and AsyncListener.
Enhancements to Existing APIs
In addition to the introduction of new concepts/techniques, the Servlet 3.0 specification also made the following enhancements to existing APIs.
HttpServletRequest
To support the multipart/form-data MIME type, the following methods have been added to the HttpServletRequest interface:
- Iterable
getParts() - Part getPart(String name)
Cookies
To avoid certain types of cross-site scripting attacks, Servlet 3.0 supports HttpOnly cookies. HttpOnly cookies are not exposed to the client-side scripting code. The following methods are added to the Cookie class to support HttpOnly cookies:
- void setHttpOnly(boolean isHttpOnly)
- boolean isHttpOnly()
ServletContext
With the addition of the following methods to the ServletContext API, Servlet 3.0 allows Servlets and filters to be programmatically added to a context:
- addServlet(String servletName, String className)
- addServlet(String servletName, Servlet servlet)
- addServlet(String servletName, Class extends Servlet> servletClass)
- addFilter(String filterName, String className)
- addFilter(String filterName, Filter filter)
- addFilter(String filterName, Class extends Filter>filterClass)
- setInitParameter (String name, String Value)?This method was added to set the context initialization parameter.
The Servlet 3.0 Specification Features
As you can see, the Servlet 3.0 specification offers a lot of interesting features, including ease of development through annotations, fewer configurations of frameworks through the introduction of web fragments, and enhanced response with the introduction of asynchronous processing. This major release is sure to attract a large developer community.
Authors’ Acknowledgements: The authors would like to sincerely thank Mr. Subrahmanya SV (VP, ECOM Research Group, E&R) for his ideas, guidance, support, and constant encouragement, and Mr. Piramanayagam Manickam (Senior Technical Architect, ECOM Research Group, E&R) for kindly reviewing this article and providing valuable comments. |