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,88 MB
Nội dung
156 CHAPTER 5 Using Struts with it in the struts-config.xml document. Because the form bean was created on the page that posted to this action, Struts validates the form based on the declara- tive validations. Failure of the validation automatically redirects to the entry JSP and fills in the form values. If the validation was successful, this action is invoked normally. To get the values entered via the form bean, we need only cast the actionForm instance that is passed to the execute() method. Once we have retrieved the value object, we pass it to the ScheduleDb to add it to the database and forward back to the listing page. Because of the automatic form validation, this action may not be executed immediately. The event type list must be present for the HTML <select> tag to access the event types. However, if the user is automatically redirected back to the JSP because of a validation error, the list will no longer be available on the request. Thus, the event type list must be added to the session before invoking the page the first time. While it is generally a bad idea to place long-lived objects on the ses- sion, this action is careful to remove it when it has completed its work. The last order of business is the forward to the next resource via the mapping object. In this case, the target is another action object via Struts, not a JSP. The ActionForward (like a RequestDispatcher ) can be directed to any web resource, not just a JSP. 5.2 Evaluating Struts As frameworks go, Struts is not overbearing. Many times, frameworks are so exten- sive that you can’t get anything done outside the context of the framework. Or, 80 percent of what you want to do is extremely easy to do in the framework, another 10 percent is possible but difficult, and the last 10 percent cannot be accom- plished because, of or in spite of, the framework. Struts is a much more light- weight framework. It fits into standard Model 2 type applications but doesn’t preclude your writing code that doesn’t need or want to fit into Struts. I estimate that Struts saves developers from having to write between 30 and 40 percent of the plumbing code normally required for a typical web application. Struts provides support for building Model 2 applications by supplying a large part of the code necessary for every web application. It includes a variety of pow- erful custom tags to simplify common operations. It offers a clean automatic vali- dation mechanism, and it eases building internationalized applications. Its disadvantages chiefly lie in its complexity. Because there are numerous moving parts in Struts, it takes some time to get used to how everything fits together. It is Summary 157 still a new framework, so you may experience some performance issues with extremely busy sites. However, my company has used it for several moderately busy web applications and been pleased with its performance and scalability, and the lack of serious bugs. Struts is now in its second release (Struts 1.1) and has garnered considerable developer support. One apparent disadvantage of Struts goes hand in hand with one of its advan- tages. To fully exploit Struts’ custom tags, you must write your JSPs in terms of Struts elements, replacing the standard HTML elements like <input> , <select> , and so on. However, one of the stated goals of the Model 2 architecture is a sepa- ration of responsibilities, ideally allowing the graphics designers to work solely on the user interface. If they are forced to use Struts tags, they can no longer use their design tools. The Jakarta web site contains links to resources for Struts. One of these is a plug-in that allows you to use custom JSP tags within Dreamweaver UltraDev, one of the more popular HTML development environments. By using this extension, your HTML developers can still drop what looks like standard HTML elements (like input s, select s, etc.), and the tool generates Struts tags. The extension is nice enough to allow the HTML developer to fill in attribute values for tags and generally work seamlessly with the Struts tags. We have used this within our com- pany, and HTML designers who know virtually nothing about Java quickly become accustomed to working in this environment. Now you can have the Model 2 advantages of separation of responsibilities and still use Struts. Check out http:// jakarta.apache.org/taglibs/doc/ultradev4-doc/intro.html for information on this and other useful Struts extensions. If you are using more recent versions of Dreamweaver, it already offers support for all custom JSP tags, which includes the Struts tags. Several Java development environments are adding support for Struts. Starting with version 8, Borland’s JBuilder development environment has wizards and other designers to facilitate Struts development. 5.3 Summary Struts has found the middle ground of being useful, powerful, but not too com- plex. Using Struts is easy to anyone familiar with Model 2, and it helps developers build highly effective web applications. This chapter covered the open-source Struts framework. We walked you through the development of the schedule appli- cation, building the parts that accommodate the framework along the way. Struts 158 CHAPTER 5 Using Struts contains many elements and can be daunting because of the perceived complex- ity, but once you understand it, it fits together nicely. This chapter covered the basic classes necessary for the application, including the boundary and entity classes. We then discussed Struts Actions, comparing them to the Parameterized Command example from chapter 4. The discussion of actions led to the description of the main Struts controller servlet; we explained how to configure it through both the web.xml and struts-config.xml files. We described how action mappings work and how the controller dispatches requests. You learned about the user interface elements of Struts, including several of the Struts custom tags. Our schedule application showed you how to create pages with little or no Java code, relying on the custom tags. You also learned about complex HTML elements like <select> , and the concept of internationalization. Next, we turned to validations and the automatic validation built into the framework. Finally, we discussed the advantages and disadvantages of using Struts. In the next chapter, we look at Tapestry, another framework for building Model 2 applications that has virtually nothing in common with Struts. 159 Tapestry This chapter covers ■ The design and architecture of Tapestry ■ Building applications using Tapestry ■ Evaluating Tapestry 160 CHAPTER 6 Tapestry Up to this point, we’ve looked at frameworks that are closely tied to the web APIs available in Java. A close tie to the web APIs is a natural preference when you’re creating a web application; however, it is not a strict requirement. As you’ll see in this chapter, Tapestry moves away from strictly web-based APIs and allows you to create web applications that feel more like traditional applications. Instead of wor- rying about such web topics as session tracking, URLs, and other minutia of HTTP and the Web in general, Tapestry builds a framework that effectively hides all these details. It uses an object model similar to traditional graphical user interface ( GUI) development. Tapestry doesn’t prevent you from accessing the servlet API, but it encapsulates it to the point where you don’t need to very often. This approach means that developers coming from a desktop development back- ground can capitalize on their skills without getting too far into web-specific APIs. The goal of the Tapestry developers is to create a highly productive framework, where you shouldn’t have to write any unnecessary, repetitive, or mechanical code. This chapter, like the other chapters highlighting frameworks, creates the schedule application using the Tapestry framework. As you will see, even though the application looks the same to the user, the internals are vastly different from the “straight” Model 2 or Struts versions. 6.1 Overview Tapestry is an open-source Java framework for creating web applications in Java. It was developed by Howard Lewis Ship and is part of the Jakarta project at Apache. You can download it at http://jakarta.apache.org/tapestry. The version we use for this chapter is 2.2; version 3 was in beta at the time this book was written. Tapestry is a large framework, more like Turbine than Struts. It provides a wealth of prebuilt components for handling such details as object pooling, session management, and HTML components. Because of the nature of the framework, it provides a high level of reusability for commonly needed elements in a web appli- cation. Coding in Tapestry is in terms of objects, properties, and methods, not URLs and query parameters. The framework handles all the low-level web details of the application. 6.2 The architecture For presentation, Tapestry uses an alternative to scripting languages, such as JSP and Velocity. It provides an all-encompassing framework using a combination of The architecture 161 Java reflection, the JavaBeans API, and HTML templates. Much of the interaction between components in Tapestry takes place through interfaces designed into the framework. The framework defines the flow of logic through the system with a collection of specifications (written as XML documents) and framework objects. A Tapestry application starts when the user accesses the application through the browser by pointing to the Tapestry ApplicationServlet . The servlet acts as the universal controller. It creates the Application Engine, which is the framework object that handles a user’s interaction with the application. An instance of the engine is created for each user and acts as a proxy for that user. The engine reads the application specification from a configuration file, which defines the pages. The engine then reads the page specification and template for the requested page to determine the contents of the page, and uses this information to render the page for the user. Most of the configuration documents are cached in mem- ory, so this process isn’t as resource intensive as it might appear. The overall archi- tecture is shown in figure 6.1. The specification documents (both application and page) are XML docu- ments. The template is an HTML document with replaceable portions. It is not a JSP or template-based view like Velocity (covered in chapter 9). Instead, the HTML elements serve as placeholders, replaced by the controls and JavaBeans Browser Application Engine ApplicationServlet <<view>> Template 1) Access 2) Creates 3) Reads Home Page 3a) References 4) Reads 4a) References 5) Renders Application Specification Figure 6.1 The application servlet bootstraps the Application Engine, which reads the specifications for the application and renders the results. 162 CHAPTER 6 Tapestry referenced in the specification document. The application servlet acts as the entry point into the framework. Once it has created the engine, there are no other parts of the “traditional” web API in a Tapestry application. Tapestry con- tains several “moving” parts. Because the framework handles so much of the application for you, it must perform a lot of work. Tapestry’s actions are driven by specification documents. The application, pages, components, and libraries are all referenced through these documents. Generally, the first access to a resource by Tapestry is through the specification doc- ument, which leads to the other resources Tapestry must load to fulfill the request. You must understand the specification documents to use Tapestry successfully. This overview shows the basics of Tapestry’s architecture and includes a work- ing application. Rather than delve immediately into the schedule application, we think Tapestry is complex enough to warrant a “Hello, World” application to give you a flavor of its moving parts. 6.3 A simple Tapestry application It is traditional when learning new language to create a “Hello, World” applica- tion to show the basic processes required to get an application up and running. We use this simple application because it includes the parts required for every Tapestry application. 6.3.1 Tapestry Hello, World The Tapestry Hello, World application consists of the application servlet, the application and Home page specifications, and the Home page template. The application servlet The entry point for a Tapestry application is the application servlet. This is the bridge between the web world and the Tapestry world. In the web application con- figuration, it is the only registered servlet. That means that it is the only point where you can connect your application to the typical kinds of facilities from the web API, such as context parameters (as you will see, a Tapestry alternative exists for these). Fortunately, the ApplicationServlet class contains several protected methods you can override to plug in such information as the Locale, log file loca- tions, and the application URL path. Listing 6.1 contains a typical web.xml file for a Tapestry application. A simple Tapestry application 163 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <context-param> <param-name>log-file-location</param-name> <param-value>c:/logs/tapestry.log</param-value> </context-param> <servlet> <servlet-name>welcome</servlet-name> <servlet-class>hellotapestry.Welcome</servlet-class> </servlet> <servlet-mapping> <servlet-name>welcome</servlet-name> <url-pattern>/welcome</url-pattern> </servlet-mapping> </web-app> The first setting in this file is a context parameter for the location of the log file. Tapestry’s treatment of logging is first rate. (For more information about logging for other frameworks, see chapter 16.) The logging configuration information can also appear in another location (discussed later in section 6.5.1), but it is tra- ditional to place it here where it is easily accessible to the application servlet. The only other entries in this configuration file are the servlet registration and the URL pattern for the servlet. The hellotapestry.Welcome servlet (listing 6.2) in this application extends ApplicationServlet . package hellotapestry; import net.sf.tapestry.ApplicationServlet; import net.sf.tapestry.RequestContext; import org.apache.log4j.ConsoleAppender; import org.apache.log4j.FileAppender; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.SimpleLayout; public class Welcome extends ApplicationServlet { Listing 6.1 The application servlet is the only registered servlet in a Tapestry application. Listing 6.2 The ApplicationServlet subclass 164 CHAPTER 6 Tapestry protected String getApplicationSpecificationPath() { return "/tutorial/hello/HelloWorld.application"; } protected void setupLogging() throws javax.servlet.ServletException { super.setupLogging(); logger.getRootLogger().addAppender( new ConsoleAppender(new SimpleLayout())); String logFileLocation = getServletContext() .getInitParameter("log-file-location"); try { logger.getRootLogger().addAppender( new FileAppender(new SimpleLayout(), logFileLocation)); } catch (IOException ex) { logger.error(ex); } logger.setLevel(Level.INFO); } } The only entry required in this servlet is the getApplicationSpecificationPath() method. The return from this method points to the application-specification doc- ument (which appears in listing 6.3). The other optional entry in the welcome servlet is an override of a protected method, setupLogging() , which is one of the protected methods you can override to customize the behavior of the framework. Tapestry uses the Jakarta log4j logging facility (discussed in chapter 16). The setupLogging() method allows you to add your own customized logging to the logging already present in Tapestry. In listing 6.2, we added both a console and a file log. The welcome servlet is where the context parameter comes into play. The application servlet is the ideal place in Tapestry to read and respond to context parameters. If no configuration is required, you can directly reference the Appli- cationServlet in web.xml without subclassing it. The application specification The next step in the Tapestry process is the processing of the application specifi- cation file. This is the document returned from the getApplicationSpecifica- tionPath() method of the application servlet. This XML document specifies the page mappings and engine used by the application. The specification for the Hello World application appears in listing 6.3. A simple Tapestry application 165 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE application PUBLIC "-//Howard Lewis Ship//Tapestry Specification 1.3//EN" "http://tapestry.sf.net/dtd/Tapestry_1_3.dtd"> <application name="Hello World Tutorial" engine-class="net.sf.tapestry.engine.SimpleEngine"> <page name="Home" specification-path="/tutorial/hello/Home.page"/> </application> The engine created for this application is an instance of the SimpleEngine class. For more complex applications, you might use a subclass of SimpleEngine to either override existing behavior or provide additional services. The other entries in the specification are the names of the pages in the application, which map to a specification path. The path in turn points to a .page file, which contains the defi- nition of a Tapestry page. A mapping in this document may also point to a new component specification (an example of which appears later in the schedule application). In this simple application, only the Home page exists. Every Tapes- try application must have a Home page; it is by definition the first page of the application and automatically launches when the Tapestry application starts. The Home page specification The page specification is a configuration document that binds together the HTML template and the components that appear on the page. Each visible page in Tap- estry consists of a combination of a page specification and the corresponding user interface template. The page specification for the Hello World application is very simple and is shown in listing 6.4. <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE page-specification PUBLIC "-//Howard Lewis Ship//Tapestry Specification 1.3//EN" "http://tapestry.sf.net/dtd/Tapestry_1_3.dtd"> <page-specification class="net.sf.tapestry.html.BasePage"/> Listing 6.3 The application specification HelloWorld.application for the Hello World project Listing 6.4 The Home page specification [...]... IRequestCycle One of the goals of Tapestry is to encapsulate much of the stateless nature of web applications through its framework classes However, the application must respond to requests because it is still a web application This behavior is handled by the IRequestCycle interface The implementing object (RequestCycle) handles a single request cycle, or an access by the client to a page in the web application... application specification file package com.nealford .art. schedtapestry.util; import import import import import import import import java. io.IOException; net.sf.tapestry.ApplicationServlet; net.sf.tapestry.RequestContext; org.apache.log4j.ConsoleAppender; org.apache.log4j.FileAppender; org.apache.log4j.Level; org.apache.log4j.Logger; org.apache.log4j.SimpleLayout; public class Welcome extends ApplicationServlet... Home page package com.nealford .art. schedtapestry.page; import import import import import import import import com.nealford .art. schedtapestry.boundary.ScheduleDb; com.nealford .art. schedtapestry.util.ScheduleException; net.sf.tapestry.IEngine; net.sf.tapestry.html.BasePage; org.apache.log4j.ConsoleAppender; org.apache.log4j.Level; org.apache.log4j.Logger; org.apache.log4j.SimpleLayout; public class Home... shows the first part of the SchedTable class Listing 6.13 The declaration and table model portion of the custom table backing class package com.nealford .art. schedtapestry.component; import import import import import import import import import import import import import com.nealford .art. schedtapestry.boundary.ScheduleDb; com.nealford .art. schedtapestry.entity.ScheduleItem; com.nealford .art. schedtapestry.page.Home;... ITableColumn[] { new StartColumn(col[1]), Method that new DurationColumn(col[2]), returns an array of new TextColumn(col[3]), ITableColumn objects new EventTypeColumn(col [4] )}); } private class StartColumn extends SimpleTableColumn { public StartColumn(String colName) { super(colName); } public Object getColumnValue(Object row) { return ((ScheduleItem) row).getStart(); } Custom column for start Scheduling... returns a list of errors in the formSubmit() method of the Add class, the request cycle returns to the Add page The Add page includes code at the top of the template for outputting the list of validation errors The results of a failed validation are shown in figure 6.8 The error output is handled by entries in both the specification and the template Listing 6.20 contains the last part of the page specification... need is generic, that a helper class already exists The last line of the method returns the simple table model constructed around the listTableDataModel and the method call to createColumnModel() Listing 6. 14 contains the remainder of this class, which includes the classes and methods that build the column model Listing 6. 14 The last part of the table definition creates the table column model private... ActionListener objects with forms in Tapestry Of course, the full complement of desktop behavior isn’t available for a web application The RequestCycle encapsulates much of the functionality that makes Tapestry an effective framework For example, it takes care of pooling page objects for reuse In other frameworks, the developer must write code to handle this Tapestry does a lot of work behind the scenes to make... typed to a particular entity (the one passed as the row) It is possible to create them as higher-level objects if there is an opportunity to reuse them The remaining method is createColumnModel() This method obtains the list of columns from the boundary class and instantiates a SimpleTableColumnModel that wraps an array of instances of the column classes defined at the bottom of the 1 84 CHAPTER 6 Tapestry... handling I Loading of pages and templates from resources I Tracking of changes to page properties and restoring of pages to prior states I Pooling of page objects The RequestCycle also handles some pooling and rendering of components The request cycle is broken into two phases The first phase is called the rewind phase This phase exists primarily to support form submissions Because of the loose coupling . open-source Java framework for creating web applications in Java. It was developed by Howard Lewis Ship and is part of the Jakarta project at Apache. You can download it at http://jakarta.apache.org/tapestry as a property of the application. Specified as a property The Tapestry framework 169 IRequestCycle One of the goals of Tapestry is to encapsulate much of the stateless nature of web applications. Several Java development environments are adding support for Struts. Starting with version 8, Borland’s JBuilder development environment has wizards and other designers to facilitate Struts development. 5.3