Bitter cache management
5.2 Antipattern: The Cacheless Cow
5.2.4 Building the model, view and controller for AddPost
The final elements of our message board are the input form called reply.jsp and the AddPostCommand and AddPostController that we use to add a post.
The AddPost input view
Here is the input form reply.jsp:
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" content="text/html>
</HEAD>
<BODY>
<FORM METHOD="post" ACTION="/servlet/bbs.AddPostController">
<P>Please enter your post.</P>
<P>
<table>
<tr>
<td> Board: </td>
<td> <b><%=request.getParameter ("board") %></b></td></tr>
<tr>
<td> Subject: </td>
<td><INPUT TYPE="text" NAME="subject"
value="<%=request.getParameter ("subject") %>" ID="subject"
SIZE="50" MAXLENGTH="50" ></td></tr>
In this case, we are using the value parameter to prepopulate the subject field.
This technique demonstrates the power of the JSP. We are easily parsing the input parameters without any complex code.
120 CHAPTER 5
Bitter cache management
<tr><td> Author: </td>
<td><INPUT TYPE="text" NAME="author" ID="author"
SIZE="20" MAXLENGTH="20" ></td></tr>
<tr><td> Post text: </td>
<td><textarea cols="50" rows="5" wrap="soft"
name="postText"></textarea></td>
</tr>
<table>
<INPUT TYPE="hidden" NAME="parent"
value="<%=request.getParameter ("parent") %>" ID="parent" >
<INPUT TYPE="hidden" NAME="board"
value="<%=request.getParameter ("board") %>" ID="board" >
<INPUT TYPE="submit" NAME="Submit" ID="Submit" VALUE="Submit">
<INPUT TYPE="reset" NAME="Reset" ID="Reset" VALUE="Reset">
</P>
</FORM>
</BODY>
</HTML>
In this example, we could have easily used HTML instead of this JSP page. We opted to use a JSP to assist with handling prepopulation of the form with input parameters. We were also able to dynamically create the text that showed the board. However, we have no controller or command, because this JSP data does not need any input from command beans.
The model for AddPost
The following classes will take the user’s responses on the reply.jsp form and add them to the database. If we’re successful, instead of returning a new JSP we’ll return the user to the ShowBoardResults.jsp view via ShowBoardCon-troller. Here is the AddPostCommand:
package bbs;
Here are the usual imports that we use in the rest of our commands:
private String author = null;
private String subject = null;
private String board = null;
private String parent = "0";
private String postText = null;
private ResultSet result;
private Connection connection = null;
private String query = null;
Antipattern: The Cacheless Cow 121
public String getAuthor() { return (String) author;
}
public String getBoard() { return (String) board;
}
public String getParent() { return parent;
}
public String getPostText() { return postText;
}
public String getQuery() { return query;
}
public String getSubject() { return (String) subject;
}
public void setAuthor(String newAuthor) { author = newAuthor;
}
public void setBoard(String newBoard) { board = newBoard;
}
public void setParent(String newParent) { parent = newParent;
}
public void setPostText(String newPostText) { postText = newPostText;
}
public void setSubject(String newSubject) { subject = newSubject;
}
Listing 5.1 contains the attributes and the get and set methods. This list is fairly long, because we have an attribute for every database field.
122 CHAPTER 5
Bitter cache management
public void initialize() throws
AddPostValidationException, IOException,
DataException { try {
if (getAuthor() == null) { throw new AddPostValidationException(
"Author field is required.");
}
if (getSubject() == null) { throw new AddPostValidationException(
"The Subject field is required.");
} if (getPostText() == null) { throw new AddPostValidationException(
"The post is empty.");
} if (getBoard() == null) { throw new AddPostValidationException(
"The board is not valid.");
}
Class.forName("COM.ibm.db2.jdbc.app.DB2Driver").newInstance();
String url = "jdbc:db2:board";
// connect with default id/password
connection = DriverManager.getConnection(url);
} catch (Throwable theException) { theException.printStackTrace();
} }
In this initialize, we introduce validation. Here, we raise our own exception, called AddPostValidationException. If at all possible, we should keep from throwing a bare exception. This new exception serves as a collection point for information about the error condition. It also clearly communicates the prob-lem with the exception name. The code annotations show the four points where we check the required fields, and if they haven’t been set, we throw a specialized exception. In a more advanced implementation, our controller would use the information in the exception and populate a bean that could be used by our standard error JSP.
Listing 5.1 Validation is a good reason to separate execute and initialize
o
Validate authoro
Validate subjecto
Validate postTexto
Validate boardAntipattern: The Cacheless Cow 123
After the validation, we connect to the database and then clean up:
public void execute()
In our execute method, we add a record to the database. The logic is notice-ably simpler than usual because we have already done the validation of the ele-ments and we catch the database exceptions elsewhere.
Statement statement = connection.createStatement();
result = statement.executeQuery(query);
result.close();
connection.close();
statement.close();
} catch (Throwable theException) { theException.printStackTrace();
} } }
We then execute the query, clean up, and catch exceptions.
The controller for AddPost
AddPostController is similar to the other commands, with a new twist: We will dispatch an existing servlet instead of a new JSP. As usual, we’ll focus on the action in performTask:
public void performTask(
HttpServletRequest request, HttpServletResponse response) { try {
String board = request.getParameter ("board");
124 CHAPTER 5
Bitter cache management
String subject = request.getParameter ("subject");
String author = request.getParameter ("author");
String postText = request.getParameter ("postText");
String parent = request.getParameter ("parent");
AddPostCommand addPost = new AddPostCommand();
try {
We are putting our add and initialize methods into their own try/catch loop. This design will allow us to catch the exceptions that we raised for vali-dation failures. In a more robust architecture, we’d create a bean from the data in our custom exception and return an appropriate error JSP.
} catch (Throwable Exception) { try {
ServletContext servletContext = getServletContext ();
RequestDispatcher dispatcher =
servletContext.getRequestDispatcher("/JSP/AddPostError.jsp");
dispatcher.forward(request, response);
request.setAttribute("AddPostCommand", addPost);
ServletContext servletContext = getServletContext ();
RequestDispatcher dispatcher =
servletContext.getRequestDispatcher("/servlet/
bbs.ShowBoardController");
dispatcher.forward(request, response);
In this case, no dynamic data is to be displayed beyond success or failure. For the success case, users would probably prefer to continue browsing the board from the ShowBoard view. Therefore, through our controller, we simply dis-patch the user to ShowBoardController. Our request object already has the requisite board parameter set, so there is no need to re-create one.
} catch (Throwable theException) { try {
java.io.PrintWriter out = response.getWriter();
out.println("<HTML>");
out.println("<HEAD><TITLE>Post List Controller</TITLE></HEAD>");
Solution: Cache 125
out.println("<BODY BGCOLOR=#C0C0C0>");
out.println("<H2>Exception Occurred</H2>");
out.println(theException);
out.println("</BODY></HTML>");
} catch (Throwable exception) { theException.printStackTrace();
} } }
The rest of the method catches our exceptions.