Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 62 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
62
Dung lượng
1,22 MB
Nội dung
218 CHAPTER 7 WebWork name="'eventType'" list="events" listKey="'key'" listValue="'event'"/> </td></tr> <tr><td> <ww:textfield label="text('input.start')" name="'start'" value='<webwork:property value="start"/>' /> </td></tr> <tr><td> <ww:textfield label="text('input.text')" name="'text'" value='<webwork:property value="text"/>' /> </td></tr> <tr><td align="right"> <input type="submit" name="Submit" value="<ww:text name="'input.submit'"/>"> </td></tr> </table> </form> </body> </html> The only dynamic values on this page are the ones placed in the HTML <select> . The <select> tag retrieves the value of events by calling AddSchedule- Item.getEvents() , as specified by the attribute list . You may notice that the getEvents() method is absent in AddScheduleItem: it is inherited from the super class AddScheduleBase . The AddScheduleEntry JSP page makes heavy use of the WebWork custom taglibs. An interesting feature of this page is the absence of HTML text elements to iden- tify the input fields. WebWork’s textfield component handles that with a prop- erty value. The name attribute of the textfield becomes the label associated with the HTML input. Note that the name actually comes from the properties file that defines the values of all the text elements. The text values properties file for this page (AddScheduleItem.properties) is shown in listing 7.8. view.title=Add Schedule Item input.start=Start input.duration=Duration input.eventType=Event Type input.text=Description Listing 7.8 The AddScheduleEntry.properties resource file Boundary-supplied events B B Scheduling in WebWork 219 input.submit=Save error.schedule.duration=Invalid duration error.schedule.text=Event must have description The other interesting characteristic of the WebWork custom tags on the View- ScheduleEntry page is the select tag. This tag uses several attributes, which are listed with their meanings in table 7.2. The AddScheduleEntry JSP page highlights the powerful triad of WebWork’s value stack, custom taglibs, and expression language. The combination of these features is greater than the sum of their parts. The resulting View page is very clean and features only view elements, but it doesn’t give up any flexibility. Saving the record The last action in the application saves the changes to the database. The Add- ScheduleEntry action appears in listing 7.9. package com.nealford.art.schedwebwork.action; import java.io.IOException; import java.util.Map; import com.nealford.art.schedwebwork.boundary.ScheduleDb; import org.apache.log4j.FileAppender; import org.apache.log4j.Logger; import org.apache.log4j.SimpleLayout; public class AddScheduleEntry extends AddScheduleBase { Table 7.2 Attributes of the select tag Attribute Value Use label text('input.eventType') The label for the field on the HTML page name 'eventType' The action field the value of the control will map to upon sub- mission of the form list events The list of objects that implement the name-value pair mapping listKey 'key' The key field of the class that implements the name-value pair mapping listValue 'event' The value field of the class that implements the name-value pair mapping Listing 7.9 The AddScheduleEntry action saves the changes to the boundary. 220 CHAPTER 7 WebWork private static final Logger logger = Logger.getLogger( AddScheduleEntry.class); static { try { logger.addAppender(new FileAppender(new SimpleLayout(), "c:/temp/sched-webwork.log")); } catch (IOException ex) { logger.error("Can't create log file"); } } protected String doExecute() throws java.lang.Exception { Map errors = scheduleItem.validate(); if (!errors.isEmpty()) return ERROR; ScheduleDb scheduleDb = getScheduleBoundary(); scheduleDb.addRecord(scheduleItem); return SUCCESS; } } The AddScheduleEntry Action class inherits most of its capabilities from AddSched- uleBase . In the doExecute() method, it validates the scheduleItem and returns the ERROR flag upon failure. If the validations pass, the record is added to the bound- ary and the SUCCESS flag returns the user to the initial application page. The validations performed here are perfunctory. The real validations take place in the individual field editors, which are covered in the next section. 7.3.4 Validations The last topic we’ll cover for the schedule application is validations. As before, the entity object contains validation code to prevent illegal values for either duration or text . You may have noticed that the View page contains no code whatsoever to handle validations. Section 7.2.5 alluded to the mechanism used by WebWork to handle validations and other field-level criteria. WebWork uses BeanInfo classes to attach additional behavior to the Action classes. The JavaBean specification allows you to register editor classes to handle validation, formatting, and any other trans- formation you want to perform on the input. Editors Two types of validations are needed for this application. Both of these validations ultimately map back to the entity, which is the keeper of all business rules (like val- idations). To that end, we’ve upgraded the entity class to include static methods Scheduling in WebWork 221 that validate each field in turn. The previous validation method is still present (although we’ve rewritten it to take advantage of the new individual validation methods). The new methods in the ScheduleItem class are shown in listing 7.10. public static String validateDuration(String duration) { int d = -1; String result = null; try { d = Integer.parseInt(duration); } catch (NumberFormatException x) { result = "Invalid number format: " + x; } if (d < MIN_DURATION || d > MAX_DURATION) result = ERR_DURATION; return result; } public static String validateText(String text) { return (text == null || text.length() < 1) ? ERR_TEXT : null; } public Map validate() { Map validationMessages = new HashMap(); String err = validateDuration(String.valueOf(duration)); if (err != null) validationMessages.put("Duration", err); err = validateText(text); if (err != null) validationMessages.put("Text", err); return validationMessages; } Now that we have cohesive validation methods, it is trivial to write custom editors that take advantage of these rules. Listing 7.11 contains the editor for duration . package com.nealford.art.schedwebwork.util; import com.nealford.art.schedwebwork.entity.ScheduleItem; import webwork.action.ValidationEditorSupport; public class DurationEditor extends ValidationEditorSupport { Listing 7.10 The ScheduleItem class has undergone an upgrade to create more cohesive validation methods. Listing 7.11 The DurationEditor handles validating a duration value against the ScheduleItem’s validation method. 222 CHAPTER 7 WebWork public void setAsText(String txt) { String error = ScheduleItem.validateDuration(txt); if (error != null) throw new IllegalArgumentException(error); setValue(txt); } } The DurationEditor class extends ValidationEditorSupport , which is a WebWork framework class. The lone method that must be implemented is setAsText() . This method can either set the value of the field or throw an IllegalArgumentEx- ception . The WebWork framework catches the exception and associates the error string from the exception with the field. Figure 7.5 shows a validation failure for both duration and text . No additional code was added to the View page. The framework automatically added the validation exception text to the field. The class to handle text valida- tion is virtually the same, so we don’t show it here. The last step in validation is the association with the property editors with the Action classes. This is done through a BeanInfo class. The BeanInfo class for AddScheduleEntry (named, not surprisingly, AddScheduleEntryBeanInfo ) appears in listing 7.12. package com.nealford.art.schedwebwork.action; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.beans.SimpleBeanInfo; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.log4j.FileAppender; import org.apache.log4j.Logger; import org.apache.log4j.SimpleLayout; public class AddScheduleEntryBeanInfo extends SimpleBeanInfo { private static final Logger logger = Logger.getLogger( AddScheduleEntryBeanInfo.class); static { try { logger.addAppender(new FileAppender(new SimpleLayout(), Listing 7.12 The AddScheduleEntryBeanInfo class registers the custom property editors to the appropriate Action class. Scheduling in WebWork 223 "c:/temp/sched-webwork.log")); } catch (IOException ex) { logger.error("Can't create log file"); } } public PropertyDescriptor[] getPropertyDescriptors() { try { List list = new ArrayList(); PropertyDescriptor descriptor; descriptor = new PropertyDescriptor("duration", AddScheduleEntry.class); descriptor.setPropertyEditorClass(com.nealford.art. schedwebwork.util.DurationEditor.class); list.add(descriptor); descriptor = new PropertyDescriptor("text", AddScheduleEntry.class); descriptor.setPropertyEditorClass(com.nealford.art. schedwebwork.util.TextEditor.class); list.add(descriptor); return (PropertyDescriptor[]) list.toArray(new PropertyDescriptor[list.size()]); } catch (Exception x) { logger.error("AddScheduleEntryBeanInfo", x); return super.getPropertyDescriptors(); } } } Figure 7.5 WebWork automatically associates the error text with the field whose validation failed. 224 CHAPTER 7 WebWork Notice that the AddScheduleEntryBeanInfo class does not import or use any class from the WebWork framework. Everything here is either standard Java or part of the logging package. This is a standard BeanInfo class, just like the one you would register for a UI widget. The lone method creates an array of PropertyDescrip- tors . A property descriptor registers a property editor to the property of a partic- ular class. In this method, we are registering the DurationEditor and TextEditor for the AddScheduleEntry class. Generic validations The validation code in the previous section reveals one of the architecture and design pitfalls faced by developers. By creating specific editors for the Duration and text fields of the ScheduleItem class, we can carefully tie the business logic val- idation to the UI. However, this becomes cumbersome if we have hundreds of fields that must be validated. If we follow this paradigm, we will have hundreds of almost identical validation editors. Three approaches help solve this problem. First, you could create several generic editors that handle the lion’s share of validations. For example, if your application needs to validate non-negative numbers in many locations, a NonNega- tiveNumber editor can easily handle the task. The second approach creates prop- erty editors that can use reflection to determine the type of the entity they are validating and call the validations automatically for the fields. Standard interfaces for entities are used to force common semantics across all entities so that they are all validated in the same way. Smart property editors can take advantage of this characteristic. The third approach uses the Decorator design pattern to decorate the entities with property editors that handle the validations. These approaches are not mutually exclusive. It is quite common to create generic validation editors to handle common situations. Interfaces are useful when you have objects that share common semantics (usually enforced by inter- faces). Decorator is useful when you have a disparate set of objects that share com- mon validation needs. 7.4 Evaluating WebWork When deciding whether to use a framework, you should consider the documenta- tion (including the samples) and the “feel” of the framework. In WebWork, the documentation and samples go hand in hand. In fact, the best documentation for the custom tags is included in the samples. Evaluating WebWork 225 The WebWork documentation is sufficient. (It is posted on the OpenSym- phony web site and is included with the download.) The creators have even gone so far as to customize the doclet used by JavaDoc to make the API JavaDoc look more like the OpenSymphony web site. However, it is a minor change and it doesn’t impede the readability. The biggest problem with the documentation is the absence of comments on many methods. The classes themselves have reason- able, if terse, comments; but many of the methods have only the standard gener- ated JavaDoc information and nothing else. While this didn’t cause me any headaches, it is a glaring deficiency in such a well-designed framework. WebWork lacks Tapestry’s excellent documentation for the custom tags. In fact, the best documentation for the custom tags was in the sample applications. This characteristic seems to be common with custom tags. The JavaDoc com- ments don’t serve custom tags very well. JSTL suffers from this same syndrome— the samples are more useful than the documentation. The WebWork documenta- tion for the custom tags is no worse than any other framework’s documentation for the same kind of tags. However, all frameworks pale in comparison to Tapestry in this area. I was looking for and never found a comprehensive list of the interactions between the value stack, expression language, and custom tags. The material is present; it is just scattered around a bit. It would be nice if it were summarized somewhere. As the application in this chapter shows, it is vitally important to understand the interaction between these constructs. Most of what I found con- cerning the interactions between these three constructs came from the tutorials and samples, not the JavaDocs. The samples are good in WebWork. They suffer a bit from poor organization. The web application resources are in one directory and the source code is in another branch entirely. Once you figure out where everything lives, the samples help considerably. One thing you should note: the samples are themselves WebWork pages, so they should be run through the servlet engine. Even though you can open the static HTML pages, some of the pages are dynamic. If you are looking at an exam- ple of a custom tag and it seems as if most of the tag code is missing, you are prob- ably not running it properly. The sample’s index page categorizes the samples well. It starts with simple capabilities samples (such as how to use the taglibs) and moves to more complex, complete applications. The last samples illustrate how to incorporate UI frame- works like Velocity into WebWork. 226 CHAPTER 7 WebWork WebWork meets its stated goals. It makes web development easier without com- promising good design and reliance on design patterns. I particularly like the combination of the value stack, expression language, and custom taglibs. Once I understood how they worked, it made writing pages simple. In fact, in one case I actually wrote some code, ran it, saw that it worked, and then had to figure out why! Some of the interactions between these three elements happen so seamlessly that they seem instinctive. 7.5 Summary This chapter covered OpenSymphony’s WebWork, a “Pull Hierarchical MVC” framework for building web applications. We discussed the value stack, the expres- sion language, and the custom properties. The interaction of these three ele- ments is the primary distinguishing characteristic of this framework. We built our schedule application in WebWork and explained the many con- figuration options, including the variety of configuration files. Then, we built the artifacts necessary to create the two pages of the schedule application. Each page in a WebWork application requires an Action class and a UI page. The UI page sets this framework apart from others because of the powerful behind-the-scenes behavior of the three key elements mentioned earlier. We showed you how WebWork uses property editors and Java’s BeanInfo mech- anism to provide a way to create custom property editors for fields. We used the editors to validate the user input on the form. Finally, we discussed the documen- tation, samples, and the “feel” of WebWork. It is a powerful framework that does not sacrifice good design or architecture. In the next chapter, we look at a commercial web framework, InternetBeans Express. 227 InternetBeans Express This chapter covers ■ The design and architecture of InternetBeans Express ■ Building applications with InternetBeans Express ■ Evaluating the framework [...]... the Add servlet package com.nealford .art. ixbeans.servlet.ui; import import import import import java. io.IOException; java. io.PrintWriter; java. util.ArrayList; java. util.Iterator; java. util.List; import import import import import javax.servlet.RequestDispatcher; javax.servlet.ServletException; javax.servlet.http.HttpServlet; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse;... all designer- generated code private void jbInit() throws Exception { column5.setColumnName("description"); column5.setDataType(com.borland.dx.dataset.Variant.STRING); column5.setPrecision (50 ); column5.setEditable(true); column5.setTableName("event"); column5.setServerColumnName("description"); column5.setSqlType(12); column5.addColumnChangeListener(new ColumnChangeAdapter() { public void validate(DataSet... event and event_type) on it The first part of the DataModule is used for the basic connectivity and the first page of the application The latter part of the DataModule is needed for validation and user input, so it will appear later Listing 8.2 shows the first part of the DataModuleSchedule Listing 8.2 The first portion of the Schedule DataModule package com.nealford .art. ixbeans.servlet.db; import import... with InternetBeans Express 8.1 Overview InternetBeans Express is a feature of the Enterprise version of JBuilder, the version that includes web development It consists of a series of components that integrate with servlets and a custom taglib for use in JSP These components are primarily concerned with the presentation tier of a web application JBuilder contains other components for handling database... in this version of the application is the RAD nature of the framework This will not be a Model 2 application—this framework is not designed to work in that context However, a reasonable separation of concerns is still possible without doing battle with the framework For the most part, we’re going to let the RAD nature of the framework dictate the architecture of the application and retrofit it to improve... com.nealford .art. ixbeans.servlet.ui; import import import import import import import import import java. io.IOException; javax.servlet.ServletException; javax.servlet.http.HttpServlet; javax.servlet.http.HttpServletRequest; javax.servlet.http.HttpServletResponse; com.borland.internetbeans.IxLink; com.borland.internetbeans.IxPageProducer; com.borland.internetbeans.IxTable; com.nealford .art. ixbeans.servlet.db.DataModuleSchedule;... using these tools you can create applications significantly faster than without them The purpose of this chapter is twofold The first is to show a RAD web development framework so that you can compare it to the others shown in the book The other goal is to find a partial way to reconcile the worlds of RAD development with the ideas prevalent in this book As in the other framework chapters, we’ll be building... that exist in the JBuilder development environment, primarily the DataExpress components The DataExpress components have existed and evolved since the first version of JBuilder They represent a solid, well-architected wrapper around Java Database Connectivity ( JDBC) Most of the behavior in DataExpress started as support for building client/server applications As the focus in Java has moved more to the...228 CHAPTER 8 InternetBeans Express Most of the frameworks and tools covered in this book are open source The Java world contains a wealth of open-source code, some of it with state -of- the -art quality However, my emphasis on open source should not suggest that commercial frameworks don’t exist Many large organizations... integrated development environment ( IDE), Borland’s JBuilder It includes a Rapid Application Development ( RAD) framework called InternetBeans Express for building web applications that leverage component-based development It builds on the already strong components that already exist in JBuilder for building client/server applications This framework presents a departure in another manner as well Most of the . advantage of these rules. Listing 7.11 contains the editor for duration . package com.nealford .art. schedwebwork.util; import com.nealford .art. schedwebwork.entity.ScheduleItem; import webwork. action.ValidationEditorSupport; public. Velocity into WebWork. 226 CHAPTER 7 WebWork WebWork meets its stated goals. It makes web development easier without com- promising good design and reliance on design patterns. I particularly. com.nealford .art. schedwebwork.action; import java. beans.BeanInfo; import java. beans.Introspector; import java. beans.PropertyDescriptor; import java. beans.SimpleBeanInfo; import java. io.IOException; import