Servlet Filter and Servlet Chain
Servlet Filter and Servlet Chain -We’ve looked at servlets that take requests from the server and provide results to the client. Servlets, on the other hand, were created as a generic server extension technology rather than one dedicated only to executing CGIlike functions.
Most web servers that implement servlets have also implemented a feature called servlet chaining, where the server routes a request through an administratordefined chain of servlets.
Servlet Chain
In the following example, describe a simple servlet built from HttpServlet that searches incoming text for a DATE> tag and replaces it with the current date. This servlet is never called on its own; rather, it is called after another servlet (such as an HTML generator) has generated the actual content.
Date Filtering Servlet Example
import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.util.*; public class DateFilter extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter out = resp.getWriter(); String contentType = req.getContentType(); if (contentType == null) return; // No incoming data // Note that if we were using MIME filtering we would have to set this to // something different to avoid an infinite loop resp.setContentType(contentType); BufferedReader br = new BufferedReader(req.getReader()); String line = null; Date d = new Date(); while ((line = br.readLine()) != null) { int index; while ((index=line.indexOf("<DATE>")) >= 0) line = line.substring(0, index) + d + line.substring(index + 6); out.println(line); } br.close(); } }
The DateFilter servlet works by reading each line of input, scanning for the text <DATE>, and replacing it with the current date. This example introduces the getReader() method of HttpServletRequest, which returns a PrintReader that points to the original request body.
Servlet Filter
The Version 2.3 of the Servlet API introduced a new method of handling requests, via the javax.servlet.Filter class. When filters are used, the servlet container creates a filter chain. This consists of zero or more Filter objects and a destination resource, which can be either a servlet or another resources available on the web server (such as an HTML or JSP file).
When a filtered resource is requested, the servlet creates a filter chain and executes the doFilter() function of the first filter in the chain, passing a ServletRequest, a ServletResponse, and the FilterChain object along with it. The request can then be processed by the filter. Noninterventionary processing is occasionally used (for example, logging request attributes or tracking a clickstream). However, the filter can also create its own copies of the ServletRequest and ServletResponse classes, overriding specific functions.
Example, AuthenticationFilter
import javax.servlet.*; import javax.servlet.http.*; import java.util.Hashtable; public class AuthenticationFilter implements Filter { private Hashtable users = null; public void init(FilterConfig config) throws javax.servlet.ServletException { users = (Hashtable)config.getServletContext().getAttribute( "enterprise.users"); if(users == null) { users = new Hashtable(5); users.put("test", "test"); } } public void doFilter( ServletRequest req, ServletResponse res, FilterChain chain) throws java.io.IOException, javax.servlet.ServletException { HttpServletRequest request = (HttpServletRequest)req; HttpSession sess = request.getSession(true); if(sess != null) { Boolean loggedIn = (Boolean)sess.getAttribute("enterprise.login"); if (loggedIn != Boolean.TRUE) { String login_name = request.getParameter("login_name"); String login_pass = request.getParameter("login_pass"); if((login_name != null) && (login_pass != null)) if(users.get(login_name).toString().equals(login_pass)) { loggedIn = Boolean.TRUE; sess.setAttribute("enterprise.login", Boolean.TRUE); sess.setAttribute("enterprise.loginname", login_name); } } if (loggedIn == Boolean.TRUE) { chain.doFilter(req, res); } else { request.setAttribute("originaluri", request.getRequestURI()); request.getRequestDispatcher("/login.jsp").forward(req, res); } } } public void destroy() { // Code cleanup would be here } }
Another example is how the JSP page displayed the login form. The crucial thing to remember is that the form returns to the original URI. The filter specifies the URI to send the form back to using the setAttribute() method of HttpServletRequest; the filter is then reapplied, and access to the resource is given if the user has provided sufficient credentials
<html><body bgcolor="white"> <% out.print ("<FORM METHOD=POST ACTION=\""+request. getAttribute("originaluri").toString() +"\">"); %> Login Name: <INPUT TYPE=TEXT NAME="login_name"><br> Password: <INPUT TYPE=PASSWORD NAME="login_pass"> <INPUT TYPE=SUBMIT VALUE="Log In"> </FORM> </body></html>
Map the filter to the paths you want to protect when configuring it. Mapping it to /* will not work because it will also protect the /login.jsp file (which the RequestDispatcher object will run via its own filter chain).