Modify the Logon.jsp file see Listing 11.18 as shown in the following code to load the logon.properties resource bundle and specify a local page variable.. Replace the Simple Tags In th
Trang 1logon.title=Simple Bloggerlogon.username=Username:
logon.password=Password:
logon.submit=Submitlogon.header=Welcome to Simple Blogger
logon.instructions=Enter your username and password to <br> log intoyour blog
logon.error.userName=Valid username is 6 to 10 characters (try
“blogger”)logon.error.password=Valid password is 6 to 10 characters (try
“blogger”)logon.error.unsuccessful=Unauthorized user, please try again
# webLogEdit webLogEdit.title=BloggerwebLogEdit.save=SavewebLogEdit.clear=ClearwebLogEdit.logout=Exit
Listing 11.19 (continued)
# JSF application.properties
# special properties global.blogPath=c:\\temp\\
Listing 11.20 JSF application.properties after conversion to JSF.
# logon.properties
title=Simple Bloggerusername=Username:
password=Password:
submit=Submitheader=Welcome to Simple Blogger
instructions=Enter your username and password to log into your blog
# error messages for the logon pageusernameError=Valid username is 6 to 10 characters (try “blogger”)passwordError=Valid password is 6 to 10 characters (try “blogger”)unsuccessfulError=Unauthorized user, please try again
usernameRequired=Username RequiredpasswordRequired=Password Required
Listing 11.21 JSF logon.properties after conversion to JSF.
Trang 2# blogEditForm.properties
title=Bloggersave=Saveclear=Clearlogout=Exitedit=editdelete=delete
Listing 11.22 JSF blogEditForm.properties after conversion to JSF.
Modify the Logon.jsp file (see Listing 11.18) as shown in the following code to load the logon.properties resource bundle and specify a local page variable.
<f:loadBundle basename=”form.bundles.logon” var=”bloggerBundle”/>
Modify the WebLogEdit.jsp file as shown in the following code to load the blogEditForm.properties resource bundle and specify a local page variable.
<f:loadBundle basename=”form.bundles.logon” var=”bloggerBundle”/>
Remove Unnecessary JavaScript
A consistent goal of JSF design is to keep programming out of the JSP pages If the Struts application being converted contains JavaScript functions, evaluate them to see if they are still needed after the conversion to JSF Remove them if possible.
Surround JSF Tags with the View Tag
In order to use JSF tags in a JSP, surround the JSP code that will use JSF tags with <f:view> and </f:view> Modify Logon.jsp and WebLogEdit jsp as shown in Listing 11.18, Step 3.
Replace the Simple Tags
In the SimpleBlogger example, replacing the Struts tags is fairly ward For simple tags, Struts to JSF conversion is easy However, for more complex tags, the replacement might not be a 1 to 1 replacement For example, the logic and nesting tags of Struts are not present in JSF Replacing logic and nesting tags would require rethinking the design of the JSP
Trang 3straightfor-Instead of replacing all the tags in a single step, we recommend using an iterative approach Do the easy ones first For example, set up the form, replace the labels, text, and text areas Save the navigation, validation, and error- handling areas until later At the end of each iteration, test the basic structure.
As shown in Listing 11.18, Step 5, begin replacing tags in the Logon.jsp and WebLogEdit.jsp files Replace <html:form> with <h:form> and
</html:form> with </h:form> tags
Continue replacing the struts tags with JSF tags For example, replace <bean: message key=”WebLogEdit.title”/> with <h:outputTextvalue=
”#{bloggerBundle.title}”/>
Add Validation Attributes or Tags
One of the biggest differences between the design of Struts and JSF is the dation of user input In Struts, the ActionForm subclasses are responsible for implementing a validate method that is automatically called by the Struts framework (if specified in the struts-config actionForward declara- tion) Errors are collected and then displayed back to the user if the set of errors is not empty.
vali-In JSF, input validation is managed by either validation tags that are included in the presentation layer or by using a validate attribute associated with input tags It should be noted that other layers in the application are still responsible for validating their own inputs But the goal of user input valida- tion is to try and catch errors before they descend the layers of the architecture See Table 11.2 for a complete list of validations shipped in JSF from Sun Microsystems.
In the Logon.jsp file, we could have added the standard Length tag (as shown in the following code) to the username and password fields However, the error messages generated from the core validation tags are standard and not customizable for a particular input tag
Trang 4we create all messages from the logon.properties resource bundle when an instance of LogonForm is created
// LogonForm.java
public class LogonForm extends Object { private String username;
private String password;
private ResourceBundle bundle;
private FacesMessage loginErrorMessage;
private FacesMessage usernameErrorMessage;
private FacesMessage passwordErrorMessage;
private FacesMessage usernameRequiredMessage;
private FacesMessage passwordRequiredMessage;
String message = bundle.getString(“unsuccessfulError”);
loginErrorMessage = new FacesMessage(FacesMessage.SEVERITY_INFO, message, null);
usernameRequiredMessage = new FacesMessage(
FacesMessage.SEVERITY_INFO, message, null);
message = bundle.getString(“passwordRequired”);
passwordRequiredMessage = new FacesMessage(
Listing 11.23 LogonForm.java validation methods.
Trang 5FacesMessage.SEVERITY_INFO, message, null);
int max = 10;
int min = 6;
String name = (String) value;
int length = name.length();
if(length < min || length > max) {
throw new ValidatorException(usernameErrorMessage);
int max = 10;
int min = 6;
String name = (String) value;
int length = name.length();
if(length < min || length > max) {
throw new ValidatorException(passwordErrorMessage);
}
return; // validation passed
}
Listing 11.23 (continued)
To finish the validation changes for the SimpleBlogger, we need to replace the Struts html:errors tag in Logon.jsp (see Listing 11.18) with the JSF h:messages tag as shown in the following code The layout=”table” attribute automatically formats multiple errors as rows in a table
<h:messages showSummary=”true” showDetail=”false” layout=”table”/>
Replace Navigation Tags
Replace navigation tags, like buttons and hypertext links, iteratively while building the navigation model and action classes, as described later in this chapter The basic process is to define the navigation model, add support for actions, replace the navigation tag, and test Using an iterative approach is best.
Trang 6Build the Navigation Model
Both Struts and JSF externalize navigation into configuration config.xml and faces-config.xml, respectively The logic behind this design is to simplify page flow modifications for an application
files—struts-For the SimpleBlogger application, we start with the UML state diagram from the analysis phase of our project, shown in Figure 11.4, to help us define our navigation requirements We can simplify this diagram if we focus on event outcomes with respect to navigation, as shown in Figure 11.7 In this dia- gram, the literal events are generalized into success or failure The net result of this effort is to minimize the number of navigation rules required We could have defined a separate rule for every literal event, but many of the rules would only differ by name
To define navigation in JSF, use the navigation-case with outcome and to-view-id tags, as shown in Listing 11.24 below.
Trang 7Figure 11.7 SimpleBlogger generalized navigation state diagram
Add the Action Handlers
Now it is time to wire the application together using our navigation rules and define methods to handle the application actions
In JSF, application actions are generated from UICommand components such as HtmlCommandButton or HtmlCommandLink, which implement the javax.faces.component.ActionSource interface The application designer can use either the action or actionListener attributes of the associated UICommand component tags to specify how actions will be handled
Two examples of using the action attribute are demonstrated below In the first case, the actual from-outcome name is specified, for example, action=
”success” Navigation is transferred to the to-view-id as specified in the faces-config.xml navigation rule (see Listing 11.24) In the second case, the action attribute delegates control to the bean and method, logon form.logon , that will process, make decisions, and route the final naviga- tion This logon bean method is responsible for handling any specific applica- tion action processing and returning the name of a from-outcome as specified in the faces-config.xml (see the logon method in Listing 11.25) // case 1:
in the Session scope and returns “success.” If the result is invalid, then it returns “failure.”
failure
successlogout
failuresuccess
Trang 8FacesContext facesContext = FacesContext.getCurrentInstance();
boolean hasErrorMessages = false;
validateRequiredFields();
hasErrorMessages = facesContext.getMessages().hasNext();
// test for valid user
boolean valid = security.isValidUser(getUsername(), getPassword());
if (!hasErrorMessages && valid) {
Map sessionMap = facesContext.getExternalContext()
FacesContext facesContext = FacesContext.getCurrentInstance();
if(username!=null && username.length()<=0) { facesContext.addMessage(null, usernameRequiredMessage);
Trang 9if(missingField) { return false;
}
return true;
}
a valid username and password, and navigate to the BlogEdit page
Converting the Blog Edit Actions involves the same basic steps as the logon Action Add support for edit, save, and delete Actions In addition, we need to load an existing blog when the BlogEditForm is first loaded (see Listing 11.26)
private String currentTimestamp;
private ArrayList blogEntries;
private BlogManager blogManager;
Listing 11.26 BlogEditForm.java action methods for save, edit, and delete (continued)
Trang 10public BlogEditForm() {initialize();
String username = (String)sessionMap.get(“username”);
ResourceBundle bundle = ResourceBundle.getBundle(
“form.bundles.application”);
String blogPath = bundle.getString(“global.blogPath”);
blogManager = new BlogManager(username, blogPath);
e.printStackTrace();
}setCurrentMessage(“”);
e.printStackTrace();
return “failure”;
}refreshForm();
return “success”;
}
public void edit(ActionEvent event) {// 1st parent is a Column, 2nd is the tableUIData table = (UIData)event.getComponent().getParent().getParent(); BlogEntry selection = (BlogEntry)table.getRowData();
if (selection != null) {setCurrentMessage(selection.getMessage());
setCurrentTimestamp(selection.getDateAsString());
Listing 11.26 (continued)
Trang 11} }
public void delete(ActionEvent event) {// 1st parent is a Column, 2nd is the tableUIData table = (UIData)event.getComponent().getParent().getParent(); BlogEntry selection = (BlogEntry)table.getRowData();
if (selection != null) {blogManager.removeBlogEntry(selection);
refreshForm();
}// Force a refresh to the UITable - bug in current JSF 1.0 beta releasetable.setValue(null);
Trang 12In order to create the BlogEditForm the first time it is called, we add a structor The constructor calls the initialize() method, which gets the username from the session scope Next, it retrieves from the application resource bundle the path to the location where the blogs are stored Finally, it creates a BlogManager and stores it in an instance variable to be reused for future requests When we declared the BlogEditForm as a managed bean,
con-we set the scope to session (see Listing 11.17) The JSF framework will create an instance of BlogEditForm for each user session in the application Had we set the scope to request, the constructor would have been called for each request, creating a new instance of BlogManager—an expensive operation
be shared between method invocations within the same Action class
In Struts Action class implementations, all shared values must be passed
as parameters between method invocations As a result, Action class design ends up being a collection of functions with no shared state This can be annoying to say the least, and typically results in writing long complex func- tions with redundant code In the real world, the cyclomatic complexity of Struts Action class methods is often high Functional decomposition is the only means available to developers to break up complexity.
JSF action design does not impose such restrictions It is left to the designer
to choose which Pattern is most effective in dealing with Action events For each of the edit, save, and delete Actions, we follow the same basic logic used in our Struts Action class implementation The edit() method retrieves the selection parameter from the request and sets the current Message to the selection The save() method invokes the blogManager to save the current message text as a new entry in the blog The delete() method retrieves the selection from the request parameter and invokes the blogManager to delete the selected message.
Replace the Struts action tags with their JSF counterparts in the WebLogEdit.jsp Begin by replacing the buttons, as shown in Listing 11.27.
<table width=”60%” border=”0” cellspacing=”0” cellpadding=”0”>
Listing 11.27 WebLogEdit.jsp commandButton tags.
Trang 13we replace the logic:iterate tag with the h:dataTable and h:column tags
The main problem in our conversion is that the basic semantics are different
in JSF and Struts They both iterate over a collection and retrieve entities ever, the JSF tag implementation assumes that it has the responsibility for ren- dering the table The Struts version leaves table controls with the HTML tags.
How-So, we begin by removing all the HTML table tag information replacing it with only the JSF tags
The dataTable tag uses the bean method getBlogEntries() to return a collection of blog entries to iterate over The var=”item” attribute assigns a local variable that is the current item in the collection.
Trang 14In our SimpleBlogger, the actionListener methods delete and edit use the ActionEvent to get the UIComponent that generated the Action Event and walk the view tree upwards by calling getParent() until they reach the table Once the table has been retrieved, the getRowData() method
is called to get the blogEntry (see Listing 11.26 for details).
At this point of the conversion, you should be able to run the JSF application
in its entirety
Summary
Because Struts and JSF applications are built using the MVC pattern, the version is conceptually easy However, as we have seen on this simple appli- cation, there remains a lot of work to do in the details
con-Learning a new set of tags and a new configuration file format is not cult If anything, the JSF implementation is cleaner and more consistent in these areas After all, it is the next generation after Struts Future releases of JSF will add new and improved tags.
Trang 15diffi-Adding the event listener Patterns to the view is a powerful improvement over Struts However, depending on the design of the Struts application, this might prove to be the most difficult to convert.
JSF is new, and when it matures we expect it will be the framework of choice The best of Struts, JSTL, and JSF will ultimately emerge as the de facto stan- dard for Java Web applications and hopefully for microdevices Time will tell.
Trang 17This appendix provides you with information on the contents of the download that accompanies this book For the latest information, please refer to the ReadMe file located in the zip file for download Here is what you will find:
■■ JUnit 3.8.1 or more (http://www.junit.org)
■■ What’s in the download
■■ Source code for the examples in the book
System Requirements
Make sure that your computer meets the minimum system requirements listed
in this section If your computer doesn’t match up to most of these ments, you may have a problem using the software recommended by the author
require-What’s on the Web Site
A P P E N D I X
Trang 18For Windows 9x, Windows 2000, Windows NT4 (with SP 4 or later),
Windows Me, or Windows XP:
■■ PC with a Pentium processor running at 600 MHz or faster
■■ At least 128 MB of total RAM installed on your computer; for best performance, we recommend at least 256 MB
■■ Ethernet network interface card (NIC) or modem with a speed of at least 28,800 bps
■■ A CD-ROM drive
■■ JDK 1.3.1 or higher (tested with Sun’s JDK)
For Linux:
■■ PC with a Pentium processor running at 600 MHz or faster
■■ At least 64 MB of total RAM installed on your computer; for best performance, we recommend at least 128 MB
■■ Ethernet network interface card (NIC) or modem with a speed of at least 28,800 bps
To place additional orders or to request information about other Wiley ucts, please call (800) 225-5945.
Trang 19Alur, Deepak, John Crupi, and Dan Malks Core J2EE Patterns: Best Practices and
Design Strategies Second Edition, Upper Saddle River, NJ: Prentice Hall
PTR, 2003.
Dudney, Bill, Stephen Asbury, Joseph Krozak, Kevin Wittkopf J2EE
AntiPat-terns Indianapolis, Indiana: Wiley Publishing, Inc 2003.
Gamma, Erich, Richard Helm, Ralph Johnson, and John Vlissides Design
Patterns: Elements of Reusable Object-Oriented Software Reading, MA:
Addison-Wesley Pub Co., 1995.
Goldberg, Adele, D Robson Smalltalk-80: The Language and Its Implementation.
Addison-Wesley, 1983.
Husted, Ted, Ed Burns, and Craig R McClanahan Struts User Guide,
http://jakarta.apache.org/struts/userGuide/index.html Apache Software Foundation, 2003.
Liskov, Barbara “Data Abstraction and Hierarchy,” OOPSLA 1987 Addendum
to the Proceedings, October 1987, pages 17–34.
References
Trang 21Index
SYMBOLS AND NUMBERS
{ } (curly braces) for value binding nism (#{ and }), 190
mecha- (dot), value binding for dot-separatedsubstrings, 190
# (pound sign) for value binding nism (#{ and }), 190
mecha-zero (0) for HTML row index, 243
A
AbstractComponentinterface, 28, 29Account Summary page (iBank), 335–336Account Summary screen specification(iBank), 322–323
AccountBeanclassaccessing an InvoiceBean, 195accessing ModifyInvoicePage’s labelsMap, 195
getTotal()method, 209source code, 191–192value binding with InvoiceBean,190–197
ViewInvoicesPageclass and, 210AccountSummary.jsp, 336
Action events See also actions; event
listeners (JSF)adding listener method to backing bean,261
binding listener methods directly, 261listener interface for, 74
listener type for, 261queuing, 261UICommandcomponent and, 74uses for, 44
action handlersBlogEditFormclass, 423–426converting Struts application to JSF,421–428
LogonFormclass, 421–423overview, 22
Struts Action objects versus, 22Actionobjects (Struts), 13, 14–15, 22ActionFormclasses (Struts), 16–18, 23,395–398, 405–408
ActionListenerinterface, 204
Apply Request Values phase and, 224
custom listeners, 224
as default listener, 224implementing methods, 261, 262–264implementing the interface, 45, 203, 262,265–268
Invoke Application phase and, 224
overview, 74processAction()method for invoking, 204, 262
actions See also Action events
application actions defined, 227defined, 179
implementing application actions,227–229