| [ Team LiB ] |
|
19.3 Initializing Shared Resources Using a ListenerThe Project Billboard application uses two business logic beans that must be available to process requests from all users; in other words, available as application scope objects. You may remember the NewsBean from Chapter 13. This bean is the repository for all news items relating to projects, used as the source for the personalized message list. The other business logic bean is called EmployeeRegistryBean. It acts as an abstraction of the database with employee information, containing methods for user authentication and retrieving and saving employee information. The EmployeeRegistryBean class is described in more detail in Chapter 20. Beans like this typically need to be initialized before they can be used. For instance, they may need a reference to a database or some other external data source and may create an initial information cache in memory to provide fast access even to the first request for data. You can include code for initialization of the shared resources in the servlet and JSP pages that need them, but a more modular approach is to place all this code in one place and let the other parts of the application work on the assumption that the resources are already initialized and available. An application lifecycle listener is a perfect tool for this type of resource initialization. Example 19-5 shows a listener suitable for the billboard application's needs. This type of listener implements the javax.servlet.ServletContextListener interface, with methods called by the container when the application starts and when it shuts down. Example 19-5. Listener for application resource initializationpackage com.ora.jsp.servlets;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.sql.*;
import com.ora.jsp.beans.emp.*;
import com.ora.jsp.beans.news.*;
import com.ora.jsp.sql.*;
public class ResourceManagerListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
ServletContext application = sce.getServletContext( );
String driverClass = application.getInitParameter("driverClass");
String jdbcURL = application.getInitParameter("jdbcURL");
DataSourceWrapper ds = null;
try {
ds = new DataSourceWrapper( );
ds.setDriverClassName(driverClass);
ds.setUrl(jdbcURL);
}
catch (Exception e) {
application.log("Error creating connection pool: ", e);
}
EmployeeRegistryBean empReg = new EmployeeRegistryBean( );
empReg.setDataSource(ds);
application.setAttribute("empReg", empReg);
NewsBean news = new NewsBean( );
application.setAttribute("news", news);
}
public void contextDestroyed(ServletContextEvent sce) {
ServletContext application = sce.getServletContext( );
application.removeAttribute("empReg");
application.removeAttribute("news");
}
}
The contextInitialized( ) method is called when the application starts, before any requests are delivered. The ServletContextEvent object passed as an argument has a method for getting a reference to the ServletContext instance for this application. The ServletContext provides a number of methods for accessing information about the web application as well as for sharing data between all application components, such as servlets, listeners, filters, and JSP pages. The first context method used in Example 19-5 is the getInitParameter( ) method. It returns the value of a context initialization parameter defined in the deployment descriptor. We look at the definition later. The listener gets the values of two initialization parameters containing information about the employee-information database: driverClass and jdbcURL. A javax.sql.DataSource instance is then created using these values. A DataSource, an interface that was introduced by the JDBC 2.0 Optional Package and is now part of JDBC 3.0 (bundled with Java SDK 1.4), provides access to JDBC database connections for retrieving and modifying database data. It can represent a connection pool, letting you reuse a set of open connections instead of opening and closing a new connection for every request. Many JDBC driver vendors offer connection pool DataSource implementations, but here we use a simple wrapper class that implements its own connection pool based on standard JDBC 1.0 classes. The wrapper class is discussed in more detail in Chapter 24, where I also describe how to use a vendor-provided DataSource implementation.[2]
Finally, the business logic beans are created. The EmployeeRegistryBean is used by the Project Billboard application instead of accessing the database directly. It's always a good idea to encapsulate database access functions in a separate class, so that you have to make changes in only one place in case the database schema is changed at some point. The bean instance is initialized with the DataSource and saved as a context attribute named empReg. Next, the NewsBean instance is created and saved as a context attribute named news. The implementation used in this example keeps all messages in memory. If a database was used instead (a likely requirement for a real application), the NewsBean would also need to be initialized with the DataSource. The listener saves references to the two beans as ServletContext attributes. This makes it easy for both servlets and JSP pages to get hold of them, as described earlier. A listener that creates and initializes shared beans should also make sure that the beans are being removed and shut down gracefully, if needed. This is done in the listener's contextDestroyed( ) method, as shown in Example 19-5. Let's look at the configuration needed to use the listener. As I mentioned earlier, the listener needs a couple of context-initialization parameters for the JDBC driver information. The listener itself must also be defined, so that the container knows which class to notify about the events. You use the following elements in the application deployment descriptor (the WEB-INF/web.xml file) for these definitions: <web-app>
<context-param>
<param-name>driverClass</param-name>
<param-value>
sun.jdbc.odbc.JdbcOdbcDriver
</param-value>
</context-param>
<context-param>
<param-name>jdbcURL</param-name>
<param-value>
jdbc:odbc:example
</param-value>
</context-param>
...
<listener>
<listener-class>
com.ora.jsp.servlets.ResourceManagerListener
</listener-class>
</listener>
<listener>
<listener-class>
com.ora.jsp.servlets.SessionCounterListener
</listener-class>
</listener>
...
</web-app>
First the context initialization parameters are defined, using <context-param> elements with nested <param-name> and <param-value> elements. Next comes the listener definition, using the <listener> element with a nested <listener-class> element. Both the ResourceManagerListener, described in Example 19-5, and the SessionCounterListener, described in Example 19-4, are defined here because both are used in the Project Billboard application. |
| [ Team LiB ] |
|