• No results found

An example combining two interfaces

In document Bitter Java (Page 118-123)

Bitter JSPs

4.3 Antipattern: Compound JSPs

4.3.2 An example combining two interfaces

In the following example, we have a Compound JSP that stems from an error condition. We will take our bulletin board example and modify it to return only the posts for a user-specified board. We will need to add an input HTML form so that the user can enter the name of the board, modify the command to

Table 4.2 Problems created by combining multiple user interfaces in a single JSP, called the Compound JSP antipattern.

Problems with Compound

JSPs Description

No separation of concerns Combining code and HTML script makes it necessary to find peo-ple with programming and designing skill. This is expensive and difficult.

Poor reuse It is harder to reuse a compound view with built-in control logic.

Harder use of tools Tools handle single-user interface screens better than multiple screens.

Lack of common error treat-ments

Users like common error windows and treatments. This design makes it more difficult to include these.

Command

JSP if (command.x = a){

else if (command.x = b){

} Servlet

Client HTML

HTML for a

HTML for b

Figure 4.1 One solution to handling multiple conditions for a servlet is to process the decision in the JSP. The result is the antipattern called the Compound JSP. Some problems are poor separation of concerns and limited reuse.

90 CHAPTER 4 Bitter JSPs

set (rather than get) the board attribute, and add a check so that if the user specifies the name of a board with no posts, he or she can make another choice.

First, the input form:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">

<HTML>

<BODY>

<FORM METHOD="post" ACTION="/servlet/bbs.CompoundJSPController">

<P>Please complete the form.</P>

<P>board <BR>

<INPUT TYPE="text" NAME="board" ID="board" SIZE="20"

MAXLENGTH="20">

</P>

<INPUT TYPE="hidden" NAME="mlname" ID="mlname" VALUE="HTML">

<P>

<INPUT TYPE="submit" NAME="Submit" ID="Submit" VALUE="Submit">

&nbsp;

<INPUT TYPE="reset" NAME="Reset" ID="Reset" VALUE="Reset">

&nbsp;

</P>

</FORM>

</BODY>

</HTML>

There is no magic here. This input form will collect a board name and invoke our controller. The “action” tag specifies our interaction controller. In this case, it will be invoked with an HTTPPOST that will call our doPost method instead of the doGet method from our previous example. Next, we have our interaction controller:

// Import for commands used by this class import bbs.CompoundJSPCommand;

We will import the command for this example. We are using the Triangle design pattern outlined in chapter 3.

public class CompoundJSPController extends javax.servlet.http.HttpServlet implements Serializable {

Antipattern: Compound JSPs 91

/**

* DoPost

* Pass post requests through to performTask */

public void doPost(

HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException { performTask(request, response);

}

This example is initiated from an input form, which calls doPost instead of doGet as in our previous example. We simply pass the response and result through to the performTask method.

/**********************************************************

* Process incoming requests for information

*

* @param request encapsulates the request to the servlet

* @param response encapsulates the response from the servlet

*/

public void performTask(

HttpServletRequest request, HttpServletResponse response) { try {

String board=request.getParameter("board");

CompoundJSPCommand postList = new CompoundJSPCommand();

postList.setBoard(board);

postList.initialize();

postList.execute();

Here, we parse the single input parameter provided by the form, and follow our design pattern by issuing sets, initialize, execute, and gets (in our controller and our JSP output page):

request.setAttribute("CompoundJSPCommand", postList);

ServletContext servletContext = getServletContext ();

RequestDispatcher dispatcher =

servletContext.getRequestDispatcher("/JSP/CompoundJSPResults.jsp");

dispatcher.forward(request, response);

} catch (Throwable theException) { theException.printStackTrace();

} } /**

* DoGet

* Pass get requests through to performTask */

92 CHAPTER 4 Bitter JSPs

public void doGet(

HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException { performTask(request, response);

} }

The rest of the controller is just like our previous examples. Our command bean has changed slightly. Our board attribute is a single string instead of a vector, with a new set method and a revised get:

protected String board = null;

public String getBoard() { return board;

}

The execute must change to reflect the modified quer y and the revised attribute type. Only the differences are shown here:

public void execute() { ...

result =

statement.executeQuery(

"SELECT subject, author, board from posts where board = '"

+ getBoard() + "'");

while (result.next()) {

subject.addElement(result.getString(SUBJECT_COLUMN));

author.addElement(result.getString(AUTHOR_COLUMN));

} ...

So far, this balloon is flying smoothly. We have addressed our separation of concerns and stayed true to our base design pattern. Listing 4.2 contains the revised JSP. Unfortunately, we are in for a hard landing. This response set is just like our last, with an additional page for a not-found condition.

<HTML>

<jsp:useBean id="CompoundJSPCommand" class="bbs.CompoundJSPCommand"

scope="request"></jsp:useBean>

<% if (CompoundJSPCommand.getSize() == 0) { %>

B

Decision 1

<HEAD>

<TITLE>Choose another board! </TITLE>

</HEAD>

<p>

Listing 4.2 The compound JSP processes decisions in the JSP

Antipattern: Compound JSPs 93

There were no posts for board <%=CompoundJSPCommand.getBoard()%>

<BODY BGCOLOR=#C0C0C0>

<FORM METHOD="post" ACTION="/servlet/bbs.CompoundJSPController">

<P>Please complete the form.</P>

<P>board <BR>

<INPUT TYPE="text" NAME="board" ID="board" SIZE="20" MAXLENGTH="20" >

</P>

<INPUT TYPE="hidden" NAME="mlname" ID="mlname" VALUE="HTML">

<P>

<INPUT TYPE="submit" NAME="Submit" ID="Submit" VALUE="Submit">

&nbsp;

<INPUT TYPE="reset" NAME="Reset" ID="Reset" VALUE="Reset">

&nbsp;

</P>

</FORM>

<% } else { %>

C

Decision 2

<HEAD>

<TITLE>Message Board Posts</TITLE>

</HEAD>

<BODY BGCOLOR=#C0C0C0>

<H1>All Messages</H1>

<P>

<p>

Board: <%=CompoundJSPCommand.getBoard()%>

<TABLE border="1">

<TR>

<TD>Subject</TD>

<TD>Author</TD>

</TR>

<% for (int _i=0; _i < CompoundJSPCommand.getSize(); _i++) { %>

<TR> <TD><%=CompoundJSPCommand.getSubject(_i) %></TD>

<TD><%=CompoundJSPCommand.getAuthor(_i) %></TD>

</TR>

<% } %>

</TABLE>

<P>

<% } %>

</BODY>

</HTML>

94 CHAPTER 4 Bitter JSPs

B

This section handles the classic not-found condition. We drop into Java to make a decision and specify which interface to present.

C

This section handles the mainline condition. The conditional logic is very distract-ing to the mainline processdistract-ing.

The readability is diminished. None of the HTML editors that I used liked the structure. My intuition says that many designers would not have a problem understanding our structure, but each additional enhancement would con-tinue to break down our separation of concerns. In general, Java code in a JSP should be used only for:

Accessing commands

Basic looping

Handling simple cosmetic output conditions, like adding an “s” to make words plural

That’s it. If you need convincing, find a ColdFusion shop that has had to maintain a complex site for two years. You’ll be scared straight. I was.

In document Bitter Java (Page 118-123)