Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Beginning Apache Struts - From Novice To Professional (2006)

.pdf
Скачиваний:
57
Добавлен:
17.08.2013
Размер:
11.68 Mб
Скачать

A P P E N D I X D

■ ■ ■

Answers

Listed in this appendix are answers to questions raised in the main text.

Chapter 1: Introduction

Question: If pieces of code that do different things are bundled separately and given standardized ways of communicating between themselves, people can maintain or work on some parts of the webapp without having to worry too much about other parts. Can you see why?

Answer: An analogy might help: think of the last time you filled in your income tax form. Not a pleasant task, but imagine how much worse it would be if you had to declare your income without such a form for guidance. Very likely, you’d miss something and there would be questions and answers bouncing back between you and your favorite IRS agent. Not a very efficient way to collect or pay taxes! The obvious magic behind tax forms is that they standardize communication between you and the IRS.

Another big advantage of using a form is that you don’t have to know how the IRS operates. For example, you don’t have to know how your income tax is processed. You only have to know how to fill the tax form. So, with tax forms, you can efficiently communicate with the IRS for the purpose of paying income tax, without having to know too much about them, or guess what information they want from you.

The same idea works for code, and applies to people who build different parts of an application. Partitioning code along lines of functionality and giving the resulting code units standardized ways of communicating between themselves (in Java terms, interfaces), simplifies the code required (just as you don’t need to know how the IRS works) and facilitates communication between the application builders, making it easier for them to build or maintain the application in parallel.

In summary, the separation of the code by functionality and the use of standardized methods of communication imply easier development and maintenance because

469

470

A P P E N D I X D A N S W E R S

A code module needs to know less about the internals of a module it communicates with.

The need to know less translates to simpler code.

Chapter 3: Understanding Scopes

The answers that follow address these questions for application, session, request, and page scopes:

Audrey is the first person to view First.jsp. What will she see?

Brenda next views First.jsp from a different machine. What does she see?

If Audrey again views First.jsp after Brenda, what will she see?

What if Brenda now loads Second.jsp directly?

Answers for application scope:

Audrey sees 12. Each page appends its number to myVariable.

Brenda sees 1212. Brenda appends a 12 to Audrey’s 12.

Audrey sees 121212.

Brenda sees 1212122. The last 2 does not have an accompanying 1 because Brenda does not load First.jsp.

Answers for session scope:

Audrey sees 12. Each page appends its number to myVariable.

Brenda sees 12. Brenda gets a clean copy of myVariable.

Audrey sees 1212, since myVariable exists for the whole session.

Brenda sees 12122. The last 2 does not have an accompanying 1 because Brenda does not load First.jsp.

A P P E N D I X D A N S W E R S

471

Answers for request scope:

Audrey sees 12. Each page appends its number to myVariable. Request-scoped variables survive a page forward.

Brenda sees 12. Brenda gets a clean copy of myVariable.

Audrey sees 12, since she’s seeing a new copy of myVariable.

Brenda sees 2. The 2 does not have a 1 preceding it because Brenda does not load

First.jsp.

Answers for page scope: Audrey and Brenda both just see 2 in each scenario, since page-scoped variables exist only on the last page called.

The variable x in <% int x = 7; %> has an implicit page scope.

Chapter 5: The MVC Design Pattern

Requirement 1: A page to collect the information about a contact

View = code that displays a form for data entry

Requirement 2: Code to check contact details (postcode, email, or required fields) after submission and display errors

Controller = code that checks the data, and display errors if any

Requirement 3: Code to store and retrieve data into a database

Controller = code that calls the Model to store data

Model = code that actually stores the data

Chapter 6: Simple Validation

Simple validation quiz answers:

Q1: Suppose validating a certain field requires a numerical calculation. Would this qualify as a simple validation? You should give clear reasons for your answer.

Answer: Generally, this would not qualify as a simple validation. One good rule for identifying a simple validation is if the validation in question could be made generic (like a check for email format). In this case, arbitrary numerical calculations are considered “data transformations” and should therefore qualify as a complex validation.

472 A P P E N D I X D A N S W E R S

Q2: When is validate() called? Before Struts populates the ActionForm or after?

Answer: validate() is called after Struts populates your ActionForm subclass.

Q3: If validate() returns an empty ActionErrors instance, will the form be redisplayed?

Answer: No, the form will not be redisplayed. There were no errors!

Q4: Rewrite Listing 6-1 so that Struts only displays the error message for the first validation error encountered.

Answer: You could insert a return errors; after each validation.

Q5: If you changed the name of one of a form’s properties (say zipcode to postcode), would you have to change the corresponding error key for ActionErrors, that is, errors.add("zipcode",...) to errors.add("postcode",...)?

Answer: You are not required to make the change, because the error keys are independent of the form property names. However, it would be wise to do so, to avoid confusion.

Q6: If your answer to Q5 was “yes,” what other changes would you have to make?

Answer: If you did make the change, you’d also have to change the property attribute on the <errors> tag. In other words, you’d have to change <html:errors property= "zipcode"/> to <html:errors property="postcode"/>.

Q7: If there were more than one validation error for a single property, which error message (if any) do you think would be displayed?

Answer: If a property had more than one error message, all error messages for that property would be displayed. This is often confusing, so the trick in Q4 is useful.

Lab 8: Contact Entry Page for LILLDEP

Step 1: Which libraries would you use?

Answer: The HTML and Bean tag libraries

Step 5: What is the name of the handler for this form?

Answer: ContactFormHandler

A P P E N D I X D A N S W E R S

473

Lab 9a: Configuring LILLDEP

Step 2: What should the name of the form handler be?

Answer: There are two ways to answer this question:

•The name by which this form will be known to Struts tags is ContactFormHandler, so the path attribute is declared as path="/ContactFormHandler". (Throughout this book, this is what I mean when I refer to the “name” of a form handler.)

•The name attribute of the form handler is ContactFormBean. This is simply a reference to the form bean for this handler. It is not the name by which this handler is called in the Struts tags.

Step 5: Give a value for the form handler’s input attribute. Where is this used? What happens if you omit this attribute from the form handler’s declaration?

Answer: The form handler’s input attribute should be /full.jsp. This value is used explicitly whenever mapping.getInputForward() is called, for example, in ContactAction.java. It is also used implicitly by Struts in order to redisplay the input page if there’s a simple validation error. If this value is omitted, then the input page does not display. A generic servlet error page is displayed instead.

Step 6: Create a forward for this form handler to the page full.jsp. What should be the name attribute of this forward? (Hint: Check the code for the Action subclass.) What happens if you omit this forward declaration?

Answer: The name attribute of the forward is success. If this value is omitted, then the “next” page does not display. A generic servlet error page is displayed instead.

Lab 9b: The MNC Page

Step 2: Add a new form handler to struts-config.xml to accept data from MNC.jsp. The (single) forward should point back to MNC.jsp. What should the name of the forward be?

Answer: The name of the forward is success.

474

A P P E N D I X D A N S W E R S

Chapter 10: More Tags

Flashback Quiz: Can you remember what the counterparts of var and items were on

<logic:iterate>?

Answer: var exposes a single element of the iteratable object, so its counterpart on <logic:iterate> is id. And, since items refers to the name of the iteratable object, its <logic:iterate> counterpart is name.

Now You Do It: Construct JSTL equivalents for equal, present, empty, lessThan, lessEqual, greaterThan, and greaterEqual, and the negatives for all of the above (notEqual, notPresent, etc.).

Answer: All the above should be trivial to construct. For example, the JSTL test for

<logic:lessThan name="myConstants" property="pi" value="3.14">

would be

test="${myConstants.pi < 3.14}"

The other tags are similarly constructed. The exception is <logic:present>. This tag tests for the presence of an item in the current request. There are two nonequivalent ways to test for this. You could use

test="${myVariable != null}"

to test if the variable myVariable reference exists. Or you could use

test="${not empty myVariable}"

This latter check will return true not only if the myVariable does not exist but also if the myVariable exists but is empty, meaning it is a zero length String, or an empty array or

Collection.

Another Struts tag with a not-so-obvious JSTL replacement is <logic:messagesPresent>. This tag tests for the presence of a Struts message. For example:

<logic:messagesPresent property="emailMsg">...

checks for the presence of a message named emailMsg. In order to emulate this tag using JSTL, we have to know where Struts messages are stored on the request object. A quick comparison of the Struts source code files involved (org.apache.struts.taglib.logic. PresentTag, org.apache.struts.taglib.logic.MessagesPresentTag, and org.apache. struts.taglib.TagUtils) shows that the tests are essentially the same. So, the previous two solutions would also apply to <logic:messagesPresent>.

A P P E N D I X D A N S W E R S

475

Lab 10a: The LILLDEP Full Listing Page

Step 4: Will you need a form bean for this action mapping?

Answer: No, because we’re not processing user input. Instead, we’re using this handler to generate the listing.

Lab 10b: Simplifying ContactForm

Step 1: If you compiled and deployed LILLDEP now, would it work? Why or why not?

Answer: No, it would not work. You also have to amend the JSPs to use the relevant <nested> tags, or change the property attributes to use nested properties.

Step 2: In either approach, what is the new base object?

Answer: In either approach, the new base object is contact. For example, using nested properties, the new property declaration for the email address is

property="contact.email"

Lab 11: Importing Data into LILLDEP

Step 1: Do you need to implement the validate() or reset() method?

Answer: Yes, you could use validate() to ensure that the uploaded file has a nonzero size, and has the right extension (.csv or .CSV). You could use reset() to call destroy() on the FormFile instance.

Step 2: What should the property attribute of <html:file> be?

Answer: <html:file property="file" />

Step 4: Define a new form handler to handle the importing. What is the path attribute of the form handler?

Answer: path="/ImportForm"

476

A P P E N D I X D A N S W E R S

Chapter 13: Review Lab

Question: If you turn the company name into a link, how will you determine which company was clicked? (Hint: Look at the source code for BaseContact.)

Answer: You’d embed the ID of the contact (determined using Contact.getId()) as a parameter in the link. This link could point to a form handler that

•Creates the appropriate Contact (you must know how to use the Criteria class to do this—see Appendix A) based on the ID embedded in the link (refer to the functions on HttpServletRequest to learn how to do this—see Appendix B)

•Puts this Contact instance into the ContactForm

•Forwards to full.jsp for display

Question: You obviously want to reuse full.jsp to display the data that’s going to be edited. Do you need to make any changes to it to support updating contact information? Why?

Answer: No changes are needed to full.jsp, since the Contact instance’s save() function (actually, on BaseContact), correctly handles updating.

Question: Can you similarly reuse ContactForm and ContactAction? Do you need to make changes to them to support updating?

Answer: Yes, we can reuse both. No changes needed, since the Contact.save() correctly handles updating. This is the power of using Model classes instead of embedding SQL in your Action subclasses.

Question: What other classes would you need to complete the editing facility? (Hint: What creates the populated form for editing?)

Answer: We need a new Action to create and populate the form. See the answer to the first question for details.

Chapter 14: Tiles

Quick Quiz: What advantage does this approach (Listings 14-5 and 14-6) have over the earlier one (Listing 14-4)?

Answer: Listing 14-4 applies a layout to a single page. It can’t be reused. More precisely, you can reuse the page in your webapp of course, but you can’t reuse the layout in your other JSP pages. To reuse the layout, you’d have to define the layout in your Tiles definitions file. This is what Listing 14-5 does; it defines a layout that may be applied to any number of pages, as it is in Listing 14-6.

A P P E N D I X D A N S W E R S

477

Chapter 15: The Validator Framework

Question: In most cases, putting in a validate() function should suffice. Use the second alternative only after much thought, since validators should be generic, if only to the problem domain of your web application. Otherwise, you’d run into potential maintenance issues. Can you see why?

Answer: If a particular validation is going to be used only once, it makes no sense to write an extension to the Validator framework. This is because the maintenance overhead for such an extension (you need to declare the new validator in validation-rules.xml, create the necessary Java code, and use the validator in validations.xml) is much higher compared to using a validate() function.

Of course, if the same validation is used many times over (i.e., the validator is generic), then the cost of repeating the code in validate(), or even refactoring necessary validator code in a separate class, is higher. The latter option might seem to be lower in cost, but you’d still have to implement validate() on each form you use.

Chapter 17: Potpourri

Question: As you should know by now, unspecified() handles the case where the requested function does not exist on PrintingAction. (Question: how can this happen?)

Answer: It can happen if there’s a bug in the JSP code (that is, the JSP code omits the dispatch parameter in the URL), or if the user manually keys in an incorrect URL (again, omitting the dispatch parameter in the URL).

unspecified() does not handle a dispatch parameter value for which the corresponding function does not exist. In this case, an Exception is thrown and unless you’ve caught it using a global (or local—see Chapter 18) exception handler, you’ll see the standard JSP error page. An alternative to using exception handlers is to extend

LookupDispatchAction (as I did in Lab 14’s TilesLookupDispatchAction) to include an unknown() function that handles this possibility.

Chapter 20: JavaServer Faces and Struts Shale

Quick Quiz: How would you do the same thing in Struts?

Answer: Use LookupDispatchAction. The JSF approach is much easier to use. Instead of going through the trouble of subclassing LookupDispatchAction and declaring special parameters in struts-config.xml, all you need to do with JSF is to tell JSF which function to call in the commandButton’s action attribute.