Section 3.6. Custom Servlet Initialization


3.6. Custom Servlet Initialization

At the beginning of this chapter, we talked about how a servlet's persistence can be used to build more efficient web applications. This is accomplished via class variables and the init( ) method. When a server loads a servlet for the first time, it calls the servlet's init( ) method and does not make any service calls until init() has finished. In the default implementation, init( ) simply handles some basic housekeeping, but a servlet can override the method to perform whatever one-time tasks are required. This often means doing some sort of I/O-intensive resource creation, such as opening a database connection. You can also use the init( ) method to create threads that perform various ongoing tasks. For instance, a servlet that monitors the status of machines on a network might create a separate thread to periodically ping each machine. When an actual request occurs, the service methods in the servlet can use the resources created in init( ). Thus, the status monitor servlet might display an HTML table with the status of the various machines.

The default init(ServletConfig) implementation is not a do-nothing method, so you should remember to always call the super.init(ServetConfig) method. If you override the parameterless version, you don't have to invoke the superclass's methodthe server calls the parameterized version, which calls the parameterless method. You can access the ServletConfig object using the getServletConfig() method.

The server passes the init( ) method a ServletConfig object, which can include specific servlet configuration parameters (for instance, the list of machines to monitor). ServletConfig encapsulates the servlet initialization parameters, which are accessed via the getInitParameter( ) and getInitParameterNames( ) methods. GenericServlet and HttpServlet both implement the ServletConfig interface, so these methods are always available in a servlet and they access the servlet's ServletConfig to retrieve these parameters. Init parameters are set using the <init-param> elements for the <servlet> in the web.xml deployment descriptor (see Appendix A).

Every servlet also has a destroy( ) method that can be overwritten. This method is called when, for whatever reason, a server unloads a servlet. You can use this method to ensure that important resources are freed or that threads are allowed to finish executing unmolested. Unlike init( ), the default implementation of destroy( ) is a do-nothing method, so you don't have to worry about invoking the superclass's destroy( ) method.

Example 3-3 shows a counter servlet that saves its state between server shutdowns. It uses the init( ) method to first try to load a default value from a servlet initialization parameter. Next the init( ) method tries to open a file named /data/counter.dat and read an integer from it. When the servlet is shut down, the destroy( ) method creates a new counter.dat file with the current hit count for the servlet.

Example 3-3. A persistent counter servlet
 import javax.servlet.*; import javax.servlet.http.*; import java.io.*;   public class LifeCycleServlet extends HttpServlet {     int timesAccessed;     public void init(ServletConfig conf) throws ServletException {       super.init(conf);       // Get initial value     try {       timesAccessed = Integer.parseInt(getInitParameter("defaultStart"));     }     catch(NullPointerException e) {       timesAccessed = 0;     }     catch(NumberFormatException e) {       timesAccessed = 0;     }       // Try loading from the disk     DataInputStream ds = null;     try {       File r = new File("./data/counter.dat");       DataInputStream ds = new DataInputStream(new FileInputStream(r));       timesAccessed = ds.readInt(  );     }     catch (FileNotFoundException e) {       // Handle error     }     catch (IOException e) {       // This should be logged     }     finally {       if (ds !=null)          try {              ds.close(  );          } catch (IOException ignored) {}   }     public void doGet(HttpServletRequest req, HttpServletResponse resp)     throws ServletException, IOException {       resp.setContentType("text/html");     PrintWriter out = resp.getWriter(  );       timesAccessed++;       out.println("<html>");     out.println("<head>");     out.println("<title>Life Cycle Servlet</title>");     out.println("</head><body>");       out.println("I have been accessed " + timesAccessed + " time[s]");     out.println("</body></html>");   }     public void destroy(  ) {       // Write the Integer to a file     File r = new File("./data/counter.dat");     DataOutputStream dout = null;     try {       dout = new DataOutputStream(new FileOutputStream(r));       dout.writeInt(timesAccessed);     }     catch(IOException e) {       // This should be logged     }     finally {       try dout.close(  ); catch (IOException ignored) {}     }   } }

3.6.1. Servlet Context Initialization

Version 2.3 of the Servlet API added support for application-level events using a listener-style interface. Classes that implement the ServletContextListener interface can be associated with a servlet context and are notified when the context is initialized or destroyed. This provides programmers with the opportunity to create application-level resources, such as database connection pools, before any servlets are initialized and to share single resources among multiple servlets using the ServletContext attribute functionality.

ServletContextListener contains two methods, contextInitialized( ) and contextDestroyed( ), which take a ServletContextEvent. Context listeners are associated with their context in the web.xml file for the web application (see Appendix A for details on configuring contexts in the web.xml file). Example 3-4 defines a listener that creates a hashtable of usernames and unencrypted passwords and associates it as a context attribute. We use it in a later example.

Example 3-4. A servlet context listener
 import javax.servlet.ServletContextListener; import javax.servlet.ServletContextEvent;   public class ContextResourceLoader implements ServletContextListener {     public void contextInitialized(ServletContextEvent sce) {     java.util.Hashtable users = new Hashtable(  );     users.put("test", "test");     users.put("admin", "bob3jk");     sce.getServletContext(  ).setAttribute("enterprise.users", users);   }     public void contextDestroyed(ServletContextEvent sce) {      // This is where we clean up resources on server shutdown/restart   } }

Obviously, a real application would manage usernames and passwords in a more robust fashion, such as by storing them in a database. In this case, we can count on the JVM to properly garbage-collect the Hashtable object. If we do something more complex (such as maintaining a pool of connections to a relational database), we would use the contextDestroyed( ) method to make sure those resources are properly freed.



Java Enterprise in a Nutshell
Java Enterprise in a Nutshell (In a Nutshell (OReilly))
ISBN: 0596101422
EAN: 2147483647
Year: 2004
Pages: 269

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net