• No results found

Creating a session-bound wrapper for connections

firewallhost

Chapter 4. Servlet Database Connections

4.1 Oracle Driver Selection

4.2.3 A Session Connection

4.2.3.1 Creating a session-bound wrapper for connections

With the servlet shown in Example 4-3, a user's database connection remains open until that user submits a form containing a parameter named logout to the servlet. That's all well and good, but what happens when the user forgets to log out before closing her browser? Or when the session times out? The answer, unfortunately, is that the connection will not be closed. It will remain open until the Oracle process monitor recognizes that the session is gone, at which point the Oracle process monitor closes the connection. This is terribly inefficient! Fortunately, there is an elegant solution to this problem. By using the HttpSessionBinding interface, you can wrap a connection object in a session-bound object that is notified when the session expires. The session-bound object can then in turn close the connection. Example 4-4 shows a wrapper class for a connection. This wrapper class is named SessionConnection.

Example 4-4. A session-bound wrapper class for a connection

import java.sql.*;

import javax.servlet.http.*;

public class SessionConnection

implements HttpSessionBindingListener {

Connection connection;

public SessionConnection( ) { connection = null;

}

public SessionConnection(Connection connection) { this.connection = connection;

}

public Connection getConnection( ) { return connection;

}

public void setConnection(Connection connection) { this.connection = connection;

}

public void valueBound(HttpSessionBindingEvent event) { if (connection != null) {

System.out.println("Binding a valid connection"); }

else {

System.out.println("Binding a null connection"); }

}

public void valueUnbound(HttpSessionBindingEvent event) { if (connection != null) {

System.out.println(

"Closing the bound connection as the session expires"); try { connection.close( ); } catch (SQLException ignore) { } }

} }

The SessionConnection class shown in Example 4-4 holds a connection and implements

the HttpSessionBindingListener interface. When you create a new Connection object, you also need to create a new SessionConnection object. You then store your new

Connection object in that SessionConnection object. Then, when a session expires, the

HttpSession object notifies the SessionConnection object that it is about to be unbound. This notification happens because the SessionConnection class implements the

HttpSessionBindingListener interface. In turn, the SessionConnection object closes the database connection so it's not left hanging in an open state after the session has ended. 4.2.3.2 Using the session bound wrapper class

Creating the SessionConnection class is not enough. You also need to code your servlet to use that class when managing connections. Example 4-5 shows a modified version of the

Login servlet shown earlier. It can now use the SessionConnection class. The servlet has been renamed SessionLogin and uses a SessionConnection object to manage

connections.

Example 4-5. An HttpSessionBindingListener session connection servlet

import java.io.*; import java.sql.*; import javax.servlet.*; import javax.servlet.http.*;

public class SessionLogin extends HttpServlet {

public void init(ServletConfig config) throws ServletException {

super.init(config); try {

// Load the driver

Class.forName("oracle.jdbc.driver.OracleDri ver").newInstance( ); }

catch (ClassNotFoundException e) { throw new UnavailableException(

"Login init() ClassNotFoundException: " + e.getMessage( )); }

catch (IllegalAccessException e) { throw new UnavailableException(

"Login init() IllegalAccessException: " + e.getMessage( )); }

catch (InstantiationException e) { throw new UnavailableException(

"Login init() InstantiationException: " + e.getMessage( )); }

}

public void doGet(

HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {

response.setContentType("text/html"); PrintWriter out = response.getWriter( ); out.println("<html>"); out.println("<head>"); out.println("<title>Login</title>"); out.println("</head>"); out.println("<body>");

HttpSession session = request.getSession( ); SessionConnection sessionConnection =

(SessionConnection)session.getAttribute("sessionconnection"); Connection connection = null;

if (sessionConnection != null) {

connection = sessionConnection.getConnection( ); }

if (connection == null) {

String userName = request.getParameter("username"); String password = request.getParamet er("password"); if (userName == null || password == null) {

// Prompt the user for her username and password

out.println("<form method= \"get\" action=\"SessionLogin\">"); out.println("Please specify the following to log in:<p >"); out.println("Username: <input type= \"text\" " +

"name=\"username\" size=\"30\"><p>");

out.println("Password: <input type= \"password\" " + "name=\"password\" size=\"30\"><p>");

out.println("<input type= \"submit\" value=\"Login\">"); out.println("</form>");

}

else {

// Create the connection try {

connection = DriverManager.getConnection(

"jdbc:oracle:thin:@dssw2k01:1521:orcl", userName, password); }

catch (SQLException e) {

out.println("Login doGet() " + e.getMessage( )); }

if (connection != null) { // Store the connection

sessionConnection = new SessionConnection( ); sessionConnection.setConnection(connection); session.setAttribute("sessionconnection", sessionConnection); response.sendRedirect("SessionLogin"); return; } }

} else {

String logout = request.getParameter("logout "); if (logout == null) {

// Test the connection Statement statement = null; ResultSet resultSet = null; String userName = null; try {

statement = connection.createStatement( ); resultSet = statement.executeQuery(

"select initcap(user) from sys.dual"); if (resultSet.next( ))

userName = resultSet.getString(1); }

catch (SQLException e) {

out.println("Login doGet() SQLException: " + e.getMessage( ) + "<p>");

}

finally {

if (resultSet != null)

try { resultSet.close( ); } catch (SQLException ignore) { } if (statement != null)

try { statement.close( ); } catch (SQLExcep tion ignore) { } }

out.println("Hello " + userName + "!<p>");

out.println("Your session ID is " + session.getId( ) + "<p>"); out.println("It was created on " +

new java.util.Date(session.getCreationTime( )) + "<p >"); out.println("It was last accessed on " +

new java.util.Date(session.getLastAccessedTime( )) + "<p>"); out.println("<form method= \"get\" action=\"SessionLogin\">"); out.println("<input type= \"submit\" name=\"logout\" " + "value=\"Logout\">");

out.println("</form>"); }

else {

// Close the connection and remove it from the session

try { connection.close( ); } catch (SQLException ignore) { } session.removeAttribute("s essionconnection");

out.println("You have been logged out."); }

}

out.println("</body>"); out.println("</html>"); }

public void doPost(

HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {

doGet(request, response); }

}

The first notable change in this servlet, with respect to the Login servlet shown in Example 4-3,

is that it uses a SessionConnection object as an attribute of the HttpSession object. You can see in the doGet( ) method that instead of getting a Connection object directly from an

HttpSession object, this servlet gets a SessionConnection object from an HttpSession

object. If the SessionConnection object is valid (i.e., it is not initialized to null), an attempt is then made using that object's getConnection( ) method to get a connection object. If no connection object exists, the doGet( ) method creates one. It then creates a new

SessionConnection object in which to store the newly created Connection object. The

SessionConnection object in turn is stored in the HttpSession object. The SessionConnection class shown in Example 4-4 contains several

System.out.println( ) method calls you can use for debugging purposes. If you compile the SessionConnection.java and SessionLogin.java files, place them into service on your servlet container, and set your servlet container's session timeout to a reasonably small period -- such as two minutes -- you can see the HttpSessionBindingListener interface in action.

As you can see from these last few examples, using the session connection strategy can add a significant amount of code to your servlet. If you don't need a connection dedicated to a user, then you are better off using a cached connection. Let's talk about that next.