1. ServletRequestEvent 2. ServletContextEvent 3. ServletRequestAttributeEvent 4. ServletContextAttributeEvent 5. HttpSessionEvent 6. HttpSessionBindingEvent Event interfaces The event interfaces are as follows: 1. ServletRequestListener 2. ServletRequestAttributeListener 3. ServletContextListener 4. ServletContextAttributeListener 5. HttpSessionListener 6. HttpSessionAttributeListener 7. HttpSessionBindingListener 8. HttpSessionActivationListener The ServletContextEvent is notified when web application is deployed on the server.
If you want to perform some action at the time of deploying the web application such as creating database connection, creating all the tables of the project etc, you need to implement ServletContextListener interface and provide the implementation of its methods Constructor of ServletContextEvent class There is only one constructor defined in the ServletContextEvent class. The web container creates the instance of ServletContextEvent after the ServletContext instance. 1. ServletContextEvent(ServletContext e) Method of ServletContextEvent class There is only one method defined in the ServletContextEvent class: 1. public ServletContext getServletContext(): returns the instance of ServletContext. There are two methods declared in the ServletContextListener interface which must be implemented by the servlet programmer to perform some action such as creating database connection etc. 1. public void contextInitialized(ServletContextEvent e): is invoked when application is deployed on the server. 2. public void contextDestroyed(ServletContextEvent e): is invoked when application is undeployed from the server. Example of ServletContextEvent and ServletContextListener In this example, we are retrieving the data from the emp32 table. To serve this, we have created the connection object in the listener class and used the connection object in the servlet. index.html 1. <a href="servlet1">fetch records</a> MyListener.java 1. import javax.servlet.*; 2. import java.sql.*; 3. 4. public class MyListener implements ServletContextListener{ 5. public void contextInitialized(ServletContextEvent event) { 6. try{ 7. Class.forName("oracle.jdbc.driver.OracleDriver"); 8. Connection con=DriverManager.getConnection( 9. "jdbc:oracle:thin:@localhost:1521:xe","system","oracle"); 10. 11. //storing connection object as an attribute in ServletContext 12. ServletContext ctx=event.getServletContext(); 13. ctx.setAttribute("mycon", con); 14. 15. }catch(Exception e){e.printStackTrace();} 16. } 17. 18. public void contextDestroyed(ServletContextEvent arg0) {} 19. } MyListener.java 1. import java.io.*; 2. import javax.servlet.*; 3. import javax.servlet.http.*; 4. import java.sql.*; 5. 6. public class FetchData extends HttpServlet { 7. 8. public void doGet(HttpServletRequest request, HttpServletResponse response) 9. throws ServletException, IOException { 10. 11. response.setContentType("text/html"); 12. PrintWriter out = response.getWriter(); 13. 14. try{ 15. //Retrieving connection object from ServletContext object 16. ServletContext ctx=getServletContext(); 17. Connection con=(Connection)ctx.getAttribute("mycon"); 18. 19. //retieving data from emp32 table 20. PreparedStatement ps=con.prepareStatement("select * from emp32", 21. ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE); 22. 23. ResultSet rs=ps.executeQuery(); 24. while(rs.next()){ 25. out.print("<br>"+rs.getString(1)+" "+rs.getString(2)); 26. } 27. 28. con.close(); 29. }catch(Exception e){e.printStackTrace();} 30. 31. out.close(); 32. } 33. } download this example (developed using Myeclipse IDE)
Example of ServletContextListener to create table of a project In this example, we are creating table of the project. So we don't need to create all the tables manually in the database. MyListener.java 1. import javax.servlet.*; 2. import java.sql.*; 3. 4. public class MyListener implements ServletContextListener{ 5. 6. public void contextInitialized(ServletContextEvent arg0) { 7. try{ 8. Class.forName("oracle.jdbc.driver.OracleDriver"); 9. Connection con=DriverManager.getConnection(" 10. jdbc:oracle:thin:@localhost:1521:xe","system","oracle"); 11. 12. String query="create table emp32(id number(10),name varchar2(40))"; 13. PreparedStatement ps=con.prepareStatement(query); 14. ps.executeUpdate(); 15. 16. System.out.println(query); 17. 18. }catch(Exception e){e.printStackTrace();} 19. } 20. 21. public void contextDestroyed(ServletContextEvent arg0) { 22. System.out.println("project undeployed"); 23. 24. } 25. } download this example HttpSessionEvent and HttpSessionListener 1. HttpSessionEvent and HttpSessionListener 2. Methods of HttpSessionListener interface 3. Example of HttpSessionEvent and HttpSessionListener to count total and current logged-in users The HttpSessionEvent is notified when session object is changed. The corresponding Listener interface for this event is HttpSessionListener.
We can perform some operations at this event such as counting total and current logged- in users, maintaing a log of user details such as login time, logout time etc. Methods of HttpSessionListener interface There are two methods declared in the HttpSessionListener interface which must be implemented by the servlet programmer to perform some action. 1. public void sessionCreated(HttpSessionEvent e): is invoked when session object is created. 2. public void sessionDestroyed(ServletContextEvent e): is invoked when session is invalidated. Example of HttpSessionEvent and HttpSessionListener to count total and current logged-in users In this example, are counting the total and current logged-in users. For this purpose, we have created three files: 1. index.html: to get input from the user. 2. MyListener.java: A listener class that counts total and current logged-in users and stores this information in ServletContext object as an attribute. 3. First.java: A Servlet class that creates session and prints the total and current logged-in users. 4. Logout.java: A Servlet class that invalidates session. index.html 1. <form action="servlet1"> 2. Name:<input type="text" name="username"><br> 3. Password:<input type="password" name="userpass"><br> 4. 5. <input type="submit" value="login"/> 6. </form> MyListener.java 1. import javax.servlet.ServletContext; 2. import javax.servlet.http.HttpSessionEvent; 3. import javax.servlet.http.HttpSessionListener; 4. 5. public class CountUserListener implements HttpSessionListener{ 6. ServletContext ctx=null; 7. static int total=0,current=0; 8. 9. public void sessionCreated(HttpSessionEvent e) { 10. total++; 11. current++; 12. 13. ctx=e.getSession().getServletContext(); 14. ctx.setAttribute("totalusers", total); 15. ctx.setAttribute("currentusers", current); 16. 17. } 18. 19. public void sessionDestroyed(HttpSessionEvent e) { 20. current--; 21. ctx.setAttribute("currentusers",current); 22. } 23. 24. } First.java 1. import java.io.IOException; 2. import java.io.PrintWriter; 3. 4. import javax.servlet.ServletContext; 5. import javax.servlet.ServletException; 6. import javax.servlet.http.HttpServlet; 7. import javax.servlet.http.HttpServletRequest; 8. import javax.servlet.http.HttpServletResponse; 9. import javax.servlet.http.HttpSession; 10. 11. public class First extends HttpServlet { 12. public void doGet(HttpServletRequest request, 13. HttpServletResponse response) 14. throws ServletException, IOException { 15. 16. response.setContentType("text/html"); 17. PrintWriter out = response.getWriter(); 18. 19. String n=request.getParameter("username"); 20. out.print("Welcome "+n); 21. 22. HttpSession session=request.getSession(); 23. session.setAttribute("uname",n); 24. 25. //retrieving data from ServletContext object 26. ServletContext ctx=getServletContext(); 27. int t=(Integer)ctx.getAttribute("totalusers"); 28. int c=(Integer)ctx.getAttribute("currentusers"); 29. out.print("<br>total users= "+t); 30. out.print("<br>current users= "+c); 31. 32. out.print("<br><a href='logout'>logout</a>"); 33. 34. out.close(); 35. } 36. 37. } Logout.java 1. import java.io.IOException; 2. import java.io.PrintWriter; 3. 4. import javax.servlet.ServletException; 5. import javax.servlet.http.HttpServlet; 6. import javax.servlet.http.HttpServletRequest; 7. import javax.servlet.http.HttpServletResponse; 8. import javax.servlet.http.HttpSession; 9. 10. 11. public class LogoutServlet extends HttpServlet { 12. public void doGet(HttpServletRequest request, 13. HttpServletResponse response) 14. throws ServletException, IOException { 15. 16. response.setContentType("text/html"); 17. PrintWriter out = response.getWriter(); 18. 19. HttpSession session=request.getSession(false); 20. session.invalidate();//invalidating session 21. 22. out.print("You are successfully logged out"); 23. 24. 25. out.close(); 26. } 27. 28. }
@WebListener public class AppContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent servletContextEvent) { ServletContext ctx = servletContextEvent.getServletContext();
String url = ctx.getInitParameter("DBURL"); String u = ctx.getInitParameter("DBUSER"); String p = ctx.getInitParameter("DBPWD");
//create database connection from init parameters and set it to context DBConnectionManager dbManager = new DBConnectionManager(url, u, p); ctx.setAttribute("DBManager", dbManager); System.out.println("Database connection initialized for Application."); }
public void contextDestroyed(ServletContextEvent servletContextEvent) { ServletContext ctx = servletContextEvent.getServletContext(); DBConnectionManager dbManager = (DBConnectionManager) ctx.getAttribute("DBManager"); dbManager.closeConnection(); System.out.println("Database connection closed for Application.");
if (authenticated) { chain.doFilter(request, response); } else {
response.setContentType("text/html"); out = response.getWriter(); out .println("<html><head><title>Authentication Res ponse</title></head><body>"); out.println("<h2>Sorry your authentication attempt failed</h2>");
out.println("</body></html>"); out.close();
} }// doFilter
public void destroy() { /* * called before the Filter instance is removed from service by the web * container */ }
//authenticate the user using JNDI and a database, fo r instance return false;
} }
Redirecting a request Another use for filters is to restrict access to resources - if a filter doesn't call FilterChain.doFilter(), the resource won't be loaded. Simply returning would send an empty document to the browser, so it's better to redirect or forward the request to a different resource. As with a servlet, there are two ways to do this. HttpServletReponse.sendRedirect() actually sends a response to the browser giving it a URL to fetch instead of the original one, which may be on a different server. The other option is to use a RequestDispatcher to load a different resource on the server instead of the resource which would have been loaded, transparently to the browser. Unfortunately the Tomcat project doesn't provide any useful examples for this, so I'm reduced to writing my own code. SecureFilter checks the current session to see whether there is a User object; if not, it forwards the request to a login form. While hardly a robust component, you can see how a more useful system could be implemented. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { boolean authorized = false; if (request instanceof HttpServletRequest) { HttpSession session = ((HttpServletRequest)request).getSession(false); if (session != null) { User user = (User) session.getAttribute("user"); if (user != null) authorized = true; } }
if (authorized) { chain.doFilter(request, response); return; } else if (filterConfig != null) { String login_page = filterConfig.getInitParameter("login_page"); if (login_page != null && !"".equals(login_page)) { filterConfig.getServletContext().getRequestDispatcher(login_page). forward(request, response); return; } }
throw new ServletException ("Unauthorized access, unable to forward to login page");
}
h2> The <filter-mapping> block Now we need to tell the servlet container when to apply the filter, which is done with a <filter-mapping> block. The filter-mapping block includes the filter-name, which must match the name given in a <filter> block, and either a URL pattern or a servlet name. Most often you will use a URL pattern, but you can also specify the name of a servlet as defined in a <servlet> block. URL patterns for filter-mappings are the same as for the <servlet-mapping> block, normally either a subpath such as "/secure/*", or a file ending like "*.gif". Exact paths may also be used, like "/filtered_page.html". To have our filter handle all requests, we'll use the following filter-mapping block: <filter-mapping> <filter-name>Timer</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
This filter will run for every single request handled by the servlet engine. In most cases this would put an unnecessary load on the server, since few filters really need to execute for every image file as well as flat HTML, JSP, and servlet calls. Using the FilterConfig object When the servlet container starts it initializes each filter by calling the init() method, passing in a FilterConfig object. This object has two main uses, obtaining initialization parameters and accessing the container's ServletContext. Initialization parameters are set in the web.xml file, in the <filter> block, and are accessed by calling FilterConfig.getInitParameter(). The names of all parameters can be retrieved with getInitParameterNames(). The ServletContext is useful for accessing data and services relating to the servlet container and the web application. For instance, it is generally better to send output to the container's log file rather than printing to standard output, as the TimerFilter code earlier in this article does. The original ExampleFilter code from the Tomcat project does this by saving a reference to FilterConfig in a class variable, and then gets the servlet context to call its log() method. Let's look at the original Tomcat ExampleFilter code to see this in action. Not only does it use ServletContext, it also uses a configuration parameter to create a request attribute that could be retrieved by a servlet, JSP, or another filter. Although not obviously useful here, this is a handy technique for passing data between the components of a web application. In its init() method the filter saves the FilterConfig object in an object variable, along with the "attribute" initialization parameter. private FilterConfig filterConfig = null; private String attribute = null;
public void init(FilterConfig filterConfig) throws ServletException {
} Then the doFilter() method uses the FilterConfig to grab the ServletContext and use its log() method to write to the log file. It also sets an attribute in the request named according to the init-parameter, whose value is the ExampleFilter object itself. This could be used in a JSP page or servlet, or a later Filter.
// Store ourselves as a request attribute (if requested) if (attribute != null) request.setAttribute(attribute, this);
// Time and log the subsequent processing long startTime = System.currentTimeMillis(); chain.doFilter(request, response); long stopTime = System.currentTimeMillis(); filterConfig.getServletContext().log (this.toString() + ": " + (stopTime - startTime) + " milliseconds");
} Overriding the request or response In most cases filters need to affect what happens later in the request process, even if later components or the resource being accessed don't know anything about the filter. A powerful way to do this is to substitute your own request or response object when calling the FilterChain.doFilter() method. The servlet specification offers special wrapper classes for this purpose, which can be subclassed to override their default behavior. The replacement class is instantiated passing in the original request or response object, so methods which aren't overridden can still be used. This technique is particularly useful for filters that need to process the raw output of the request, for example encrypting, converting, or compressing the response data. Once again the Tomcat folks offer a good example of how to do this with CompressionFilter. Since most web browsers can automatically handle compressed pages, CompressionFilter compresses large pages on the fly. This can be applied not only to static HTML pages, but also HTML (or other format) output generated by servlets or JSP pages. If CompressionFilter determines that the browser supports compression, it wraps the response with a CompressionServletResponseWrapper, which is a subclass of HttpServletResponseWrapper. Whatever final resource is accessed by the request will be sent to the browser by calling ServletResponse.getOutputStream() or ServletResponse.getWriter() to obtain a writer or stream to feed the output into. So the response wrapper overrides these methods, replacing the stream with a custom CompressionResponseStream that uses java.util.zip.GZIPOutputStream to compress whatever is written to it, or returning a writer which employs that same stream. Here is the portion of CompressionFilter.doFilter() which actually wraps the response. if (response instanceof HttpServletResponse) { CompressionServletResponseWrapper wrappedResponse = new CompressionServletResponseWrapper((HttpServletResponse)response); wrappedResponse.setCompressionThreshold(compressionThreshold); if (debug > 0) { System.out.println("doFilter gets called with compression"); } try { chain.doFilter(request, wrappedResponse); } finally { wrappedResponse.finishResponse(); } return; } The implementation of the custom output stream is actually more sophisticated than this. It waits to ensure the returned content is large enough to be worth compressing, and then uses the compression stream or a normal stream accordingly.