| <?xml version="1.0"?> |
| <document url="./building_view.xml"> |
| |
| <properties> |
| <author>Craig R. McClanahan</author> |
| <author>Mike Schachter</author> |
| <author>Ted Husted</author> |
| <author>Martin Cooper</author> |
| <author>Ed Burns</author> |
| <title>The Struts User's Guide - Building View Components</title> |
| </properties> |
| |
| <body> |
| <chapter name="3. Building View Components" href="building_view"> |
| |
| <section name="3.1 Overview" href="overview"> |
| |
| <p> |
| This chapter focuses on the task of building the <i>View</i> components |
| of the application, which will primarily be created using JavaServer Pages |
| (JSP) technology. In particular, Struts provides support for building |
| internationalized applications, as well as for interacting with input forms. |
| Several other topics related to the View components are briefly discussed. |
| </p> |
| |
| </section> |
| |
| <section name="3.2 Internationalized Messages" href="i18n"> |
| |
| <p> |
| A few years ago, application developers could count on having to support |
| only residents of their own country, who are used to only one (or sometimes |
| two) languages, and one way to represent numeric quantities like dates, |
| numbers, and monetary values. However, the explosion of application |
| development based on web technologies, as well as the deployment of such |
| applications on the Internet and other broadly accessible networks, have |
| rendered national boundaries invisible in many cases. This has translated |
| (if you will pardon the pun) into a need for applications to support |
| <i>internationalization</i> (often called "i18n" because 18 is the number of |
| letters in between the "i" and the "n") and <i>localization</i>. |
| </p> |
| |
| <p> |
| Struts builds upon the Java platform to provide assistance |
| for building internationalized and localized applications. The key concepts |
| to become familiar with are: |
| </p> |
| |
| <ul> |
| <li><b>Locale</b> - The fundamental Java class that supports |
| internationalization is <code>java.util.Locale</code>. Each |
| <code>Locale</code> represents a particular choice of country and |
| language (plus an optional language variant), and also a set of |
| formatting assumptions for things like numbers and dates.</li> |
| <li><b>ResourceBundle</b> - The <code>java.util.ResourceBundle</code> class |
| provides the fundmental tools for supporting messages in multiple |
| languages. See the Javadocs for the <code>ResourceBundle</code> class, |
| and the information on Internationalization in the documentation bundle |
| for your JDK release, for more information.</li> |
| <li><b>PropertyResourceBundle</b> - One of the standard implementations of |
| <code>ResourceBundle</code> allows you to define resources using the |
| same "name=value" syntax used to initialize properties files. This is |
| very convenient for preparing resource bundles with messages that are |
| used in a web application, because these messages are generally text |
| oriented.</li> |
| <li><b>MessageFormat</b> - The <code>java.text.MessageFormat</code> class |
| allows you to replace portions of a message string (in this case, |
| one retrieved from a resource bundle) with arguments specified at |
| run time. This is useful in cases where you are creating a sentence, |
| but the words would appear in a different order in different languages. |
| The placeholder string <code>{0}</code> in the message is replaced by |
| the first runtime argument, <code>{1}</code> is replaced by the second |
| argument, and so on.</li> |
| <li><b>MessageResources</b> - The Struts class |
| <code><a href="api/org/apache/struts/util/MessageResources.html">org.apache.struts.util.MessageResources</a></code> lets you treat |
| a set of resource bundles like a database, and allows you to request |
| a particular message string for a particular Locale (normally one |
| associated with the current user) instead of for the default Locale |
| the server itself is running in.</li> |
| </ul> |
| |
| <p> |
| Please note that the i18n support in a framework like Struts is limited to the |
| <b>presentation</b> of internationalized text and images to the user. |
| Support for Locale specific <b>input methods</b> (used with languages |
| such as Japanese, Chinese, and Korean) is left up to the client device, which |
| is usually a web browser. |
| </p> |
| |
| <p> |
| For an internationalized application, follow the steps described in |
| the Internationalization document in the JDK documentation bundle for your |
| platform to create a properties file containing the messages for each |
| language. An example will illustrate this further: |
| </p> |
| |
| <p> |
| Assume that your source code is created in package |
| <code>com.mycompany.mypackage</code>, so it is stored in a directory |
| (relative to your source directory) named |
| <code>com/mycompany/mypackage</code>. To create a resource bundle called |
| <code>com.mycompany.mypackage.MyResources</code>, you would create the |
| following files in the <code>com/mycompany/mypackage</code> directory: |
| </p> |
| |
| <ul> |
| <li><b>MyResources.properties</b> - Contains the messages in the default |
| language for your server. If your default language is English, you |
| might have an entry like this: |
| <code>prompt.hello=Hello</code></li> |
| <li><b>MyResources_xx.properties</b> - Contains the same messages in the |
| language whose ISO language code is "xx" (See the ResourceBundle |
| Javadoc page for a link to the current list). For a French version |
| of the message shown above, you would have this entry: |
| <code>prompt.hello=Bonjour</code> |
| You can have resource bundle files for as many languages as you need.</li> |
| </ul> |
| |
| <p> |
| When you configure the controller servlet in the web application |
| deployment descriptor, one of the things you will need to define in |
| an initialization parameter is the base name of the resource bundle |
| for the application. In the case described above, it would be |
| <code>com.mycompany.mypackage.MyResources</code>. |
| </p> |
| <pre> |
| <servlet> |
| <servlet-name>action</servlet-name> |
| <servlet-class>org.apache.struts.action.ActionServlet</servlet-class> |
| <init-param> |
| <param-name>application</param-name> |
| <param-value>com.mycompany.mypackage.MyResources</param-value> |
| </init-param> |
| <.../> |
| </servlet> |
| </pre> |
| |
| <p> |
| The important thing is for the resource bundle to be found on the |
| class path for your application. Another approach is to store |
| the <code>MyResources.properties</code> file in your application's |
| <code>classes</code> folder. You can then simply specify "myResources" as the |
| application value. Just be careful it is not deleted if your |
| build script deletes classes as part of a "clean" target. |
| </p> |
| <p> |
| If it does, here is an Ant task to run when compiling your application |
| that copies the contents of a <code>src/conf</code> |
| directory to the <code>classes</code> directory: |
| </p> |
| <pre> |
| <!-- Copy any configuration files --> |
| <copy todir="classes"> |
| <fileset dir="src/conf"/> |
| </copy> |
| </pre> |
| </section> |
| |
| <section name="3.3 Forms and FormBean Interactions" href="form_beans"> |
| <p> |
| At one time or another, most web developers have built forms using |
| the standard capabilities of HTML, such as the <code><input></code> |
| tag. Users have come to expect interactive applications to have certain |
| behaviors, and one of these expectations relates to error handling -- if |
| the user makes an error, the application should allow them to fix just what |
| needs to be changed -- without having to re-enter any of the rest of the |
| information on the current page or form. |
| </p> |
| |
| <p> |
| Fulfilling this expectation is tedious and cumbersome when coding with |
| standard HTML and JSP pages. For example, an input element for a |
| <code>username</code> field might look like this (in JSP): |
| </p> |
| |
| <pre> |
| <input type="text" name="username" |
| value="<%= loginBean.getUsername() %>"/> |
| </pre> |
| |
| <p> |
| which is difficult to type correctly, confuses HTML developers who are |
| not knowledgeable about programming concepts, and can cause problems with |
| HTML editors. Instead, Struts provides a comprehensive facility for |
| building forms, based on the Custom Tag Library facility of JSP 1.1. |
| The case above would be rendered like this using Struts: |
| </p> |
| |
| <pre> |
| <html:text property="username"/> |
| </pre> |
| |
| <p> |
| with no need to explicitly refer to the JavaBean from which the initial |
| value is retrieved. That is handled automatically by the framework. |
| </p> |
| <p> |
| HTML forms are sometimes used to upload other files. Most browsers |
| support this through a <input type="file"> element, that generates |
| a file browse button, but it's up to the developer to handle the incoming |
| files. Struts handles these "multipart" forms in a way identical to |
| building normal forms. In the next section, we will cover using Struts to |
| create a simple login form, and also a simple mulitpart form. |
| </p> |
| </section> |
| |
| <section name="3.3.1 Building Forms With Struts" href="forms"> |
| |
| <p> |
| A complete example of a login form will illustrate how Struts |
| makes dealing with forms much less painful than using straight HTML |
| and standard JSP facilities. Consider the following page (based on the |
| example application included with Struts) named <code>logon.jsp</code>: |
| </p> |
| <hr/> |
| <pre> |
| <%@ page language="java" %> |
| <%@ taglib uri="/WEB-INF/struts-html.tld" |
| prefix="html" %> |
| <%@ taglib uri="/WEB-INF/struts-bean.tld" |
| prefix="bean" %> |
| <html:html> |
| <head> |
| <title> |
| <bean:message key="logon.title"/> |
| </title> |
| <body bgcolor="white"> |
| <html:errors/> |
| <html:form action="/logon" focus="username"> |
| <table border="0" width="100%"> |
| <tr> |
| <th align="right"> |
| <html:message key="prompt.username"/> |
| </th> |
| <td align="left"> |
| <html:text property="username" |
| size="16"/> |
| </td> |
| </tr> |
| <tr> |
| <th align="right"> |
| <html:message key="prompt.password"/> |
| </th> |
| <td align="left"> |
| <html:password property="password" |
| size="16"/> |
| </td> |
| </tr> |
| <tr> |
| <td align="right"> |
| <html:submit> |
| <bean:message key="button.submit"/> |
| </html:submit> |
| </td> |
| <td align="right"> |
| <html:reset> |
| <bean:message key="button.reset"/> |
| </html:reset> |
| </td> |
| </tr> |
| </table> |
| </html:form> |
| </body> |
| </html:html> |
| </pre> |
| <hr/> |
| <p> |
| The following items illustrate the key features of form handling in Struts, |
| based on this example: |
| </p> |
| |
| <ul> |
| <li>The <code>taglib</code> directive tells the JSP page compiler where to |
| find the <i>tag library descriptor</i> for the Struts tag library. In |
| this case, we are using <code>bean</code> as the prefix that identifies |
| tags from the struts-bean library, and "html" as the prefix that identifies |
| tags from the struts-html library. Any desired prefix can be used.</li> |
| <li>This page uses several occurrences of the |
| message tag to look up internationalized |
| message strings from a <code>MessageResources</code> object containing |
| all the resources for this application. For this page to work, the |
| following message keys must be defined in these resources: |
| <ul> |
| <li><b>logon.title</b> - Title of the logon page</li> |
| <li><b>prompt.username</b> - A "Username:" prompt string</li> |
| <li><b>prompt.password</b> - A "Password:" prompt string</li> |
| <li><b>button.submit</b> - "Submit" for the button label</li> |
| <li><b>button.reset</b> - "Reset" for the button label</li> |
| </ul> |
| When the user logs on, the application can store a <code>Locale</code> |
| object in the user's session. This <code>Locale</code> will be used |
| to select messages in the appropriate language. This makes it easy to |
| implement giving the user an option to switch languages -- simply change |
| the stored <code>Locale</code> object, and all messages are switched |
| automatically.</li> |
| <li>The errors tag displays any error |
| messages that have been stored by a business logic component, or nothing |
| if no errors have been stored. This tag will be described further |
| below.</li> |
| <li>The form tag renders an HTML |
| <code><form></code> element, based on the specified attributes. |
| It also associates all of the fields within this form with a session |
| scoped FormBean that is stored under the key <code>logonForm</code>. |
| The Struts developer provides the Java implementation of this form |
| bean, subclassing the Struts class <code>ActionForm</code>. |
| This bean is used to provide initial values for all of the input |
| fields that have names matching the property names of the bean. |
| If an appropriate bean is not found, a new one will be created |
| automatically, using the specified Java class name. |
| <li>The form bean can also be specified in the Struts configuration file, |
| in which case the Name and Type can be omitted |
| here. See "<a href="building_controller.html#config">The Action Mappings |
| Configuration File</a>" for details.)</li> |
| </li> |
| <li>The text tag renders an HTML |
| <code><input></code> element of type "text". In this case, |
| the number of character positions to occupy on the browser's screen |
| has been specified as well. When this page is executed, the current |
| value of the <code>username</code> property of the corresponding bean |
| (that is, the value returned by <code>getUsername()</code>).</li> |
| <li>The password tag is used similarly. |
| The difference is that the browser will echo asterisk characters, |
| instead of the input value, as the user types their password.</li>. |
| <li>The submit and |
| reset tags generate the corresponding |
| buttons at the bottom of the form. The text labels for each button |
| are created using message tags, |
| as with the prompts, so that these values are internationalized.</li> |
| </ul> |
| |
| <p> |
| Handling multipart forms is also easy. Obviously when you create a multipart |
| form you're creating a form that has at least one input of type "file". The first step to |
| creating a multipart form is to utilize the struts-html taglib to create the presentation |
| page: |
| </p> |
| |
| <hr/> |
| <pre> |
| <%@page language="java"> |
| <%@taglib uri="/WEB-INF/struts-html.tld" |
| prefix="html"> |
| <html:form action="uploadAction.do"> |
| Please Input Text: |
| <html:text property="myText"><br/> |
| Please Input The File You Wish to Upload:<br/> |
| <html:file property="myFile"><br /> |
| <html:submit /> |
| </html:form> |
| </pre> |
| <hr/> |
| <p> |
| The next step is to create your ActionForm bean: |
| </p> |
| |
| <hr/> |
| <pre> |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| import org.apache.struts.action.ActionForm; |
| import org.apache.struts.action.ActionMapping; |
| import org.apache.struts.upload.FormFile; |
| public class UploadForm extends ActionForm { |
| protected String myText; |
| protected FormFile myFile; |
| public void setMyText(String text) { |
| myText = text; |
| } |
| public String getMyText() { |
| return myText; |
| } |
| public void setMyFile(FormFile file) { |
| myFile = file; |
| } |
| public FormFile getMyFile() { |
| return myFile; |
| } |
| } |
| </pre> |
| <hr/> |
| <p> |
| Look at the <a href="../api/index.html">Javadocs</a> for FormFile to see the |
| methods it exposes to manipulate files in file uploading. Also look at the |
| Javadocs for ActionServlet and ActionMapping for the various parameters |
| you can specify to change how files are uploaded. Basically in your |
| peform() method in your action class you would call <code>((UploadForm) form).getMyFile()</code> |
| to retrieve the FormFile and do what you want with it. |
| </p> |
| |
| </section> |
| |
| <section name="3.3.2 Input Field Types Supported" href="form_input"> |
| |
| <p> |
| Struts defines HTML tags for all of the following types of input fields, |
| with hyperlinks to the corresponding reference information. |
| </p> |
| |
| <ul> |
| <li><a href="../struts-html.html#checkbox">checkboxes</a></li> |
| <li><a href="../struts-html.html#hidden">hidden</a> fields</li> |
| <li><a href="../struts-html.html#password">password</a> input fields</li> |
| <li><a href="../struts-html.html#radio">radio</a> buttons</li> |
| <li><a href="../struts-html.html#reset">reset</a> buttons</li> |
| <li><a href="../struts-html.html#select">select</a> lists with embedded option or options items</li> |
| <li><a href="../struts-html.html#option">option</a></li> |
| <li><a href="../struts-html.html#options">options</a></li> |
| <li><a href="../struts-html.html#submit">submit</a> buttons</li> |
| <li><a href="../struts-html.html#text">text</a> input fields</li> |
| <li><a href="../struts-html.html#textarea">textareas</a></li> |
| </ul> |
| |
| <p> |
| In every |
| case, a field tag must be nested within a <code>form</code> tag, so that |
| the field knows what bean to use for initializing displayed values. |
| </p> |
| </section> |
| |
| <section name="3.3.3 Other Useful Presentation Tags" href="presentation_tags"> |
| |
| <p> |
| There are several tags useful for creating presentations, consult the documentation |
| on each specific tag library, along with the Tag Developers Guides, for more |
| information: |
| </p> |
| |
| <ul> |
| |
| <li>[logic] <a href="../struts-logic.html#iterate">iterate</a> repeats its tag body once |
| for each element of a specified collection (which can be an Enumeration, |
| a Hashtable, a Vector, or an array of objects).</li> |
| <li>[logic] <a href="../struts-logic.html#present">present</a> depending on which attribute |
| is specified, this tag checks the current request, and evaluates the nested |
| body content of this tag only if the specified value is present. Only one of |
| the attributes may be used in one occurrence of this tag, unless you use the |
| property attribute, in which case the name attribute is also required. The |
| attributes include cookie, header, name, parameter, property, role, scope, |
| and user. |
| </li> |
| <li>[logic] <a href="../struts-logic.html#notPresent">notPresent</a> the companion tag to |
| present, notPresent provides the same functionality when the specified attribute |
| is not present.</li> |
| <li>[html] <a href="../struts-html.html#link">link</a> generates a HTML <a> element |
| as an anchor definition or a hyperlink to the specified URL, and automatically |
| applies URL encoding to maintain session state in the absence of |
| cookie support.</li> |
| <li>[html] <a href="../struts-html.html#img">img</a> generates a HTML <img> element |
| with the ability to dynamically modify the URLs specified by the "src" and |
| "lowsrc" attributes in the same manner that <html:link> can. |
| </li> |
| <li>[bean] <a href="../struts-bean.html#parameter">parameter</a> retrieves the value of the |
| specified request parameter, and defines the result as a page scope attribute of |
| type String or String[].</li> |
| </ul> |
| </section> |
| |
| <section name="3.3.4 Automatic Form Validation" href="form_validation"> |
| |
| <p> |
| In addition to the form and bean interactions described above, Struts |
| offers an additional facility to validate the input fields it has received. |
| To utilize this feature, override the following method in your ActionForm |
| class: |
| </p> |
| |
| <pre>public ActionErrors |
| validate(ActionMapping mapping, |
| HttpServletRequest request); |
| </pre> |
| |
| <p> |
| The validate() method is called by the controller servlet after the bean |
| properties have been populated, but before the corresponding action class's |
| <code>perform()</code> method is invoked. The <code>validate()</code> method |
| has the following options: |
| </p> |
| |
| <ul> |
| <li>Perform the appropriate validations and find no problems -- Return either |
| <code>null</code> or a zero-length ActionErrors instance, and the controller |
| servlet will proceed to call the <code>perform()</code> method of the |
| appropriate <code>Action</code> class.</li> |
| <li>Perform the appropriate validations and find problems -- Return an ActionErrors |
| instance containing <code>ActionError</code>'s, which are classes that contain |
| the error message keys (into the application's |
| <code>MessageResources</code> bundle) that should be displayed. The |
| controller servlet will store this array as a request attribute suitable |
| for use by the <code><html:errors></code> tag, and will forward |
| control back to the input form (identified by the <code>input</code> |
| property for this <code>ActionMapping</code>).</li> |
| </ul> |
| |
| <p> |
| As mentioned earlier, this feature is entirely optional. The default implementation |
| of the validate() method returns <code>null</code>, and the controller servlet |
| will assume that any required validation is done by the action class. |
| </p> |
| <p> |
| One common approach is to perform simple, prima facia validations using the |
| ActionForm validate() method, and then handle the "business logic" validation |
| from the Action. |
| </p> |
| <p> |
| An optional package for performing ActionForm validations is available in the |
| Nightly Build and from <a href="http://home.earthlink.net/~dwinterfeldt/"> |
| David Winterfeldt's Web site</a>. |
| </p> |
| </section> |
| |
| <section name="3.4 Other Presentation Techniques" href="other_presentations"> |
| |
| <p> |
| Although the look and feel of your application can be completely constructed |
| based on the standard capabilities of JSP and the Struts custom tag library, |
| you should consider employing other techniques that will improve component |
| reuse, reduce maintenance efforts, and/or reduce errors. Several options |
| are discussed in the following sections. |
| </p> |
| </section> |
| |
| <section name="3.4.1 Application-Specific Custom Tags" href="custom_tags"> |
| |
| <p> |
| Beyond using the custom tags provided by the Struts library, it is easy |
| to create tags that are specific to the application you are building, to |
| assist in creating the user interface. The example application included with |
| Struts illustrates this principle by creating the following tags unique to |
| the implementation of this application: |
| </p> |
| |
| <ul> |
| <li><b>checkLogon</b> - Checks for the existence of a particular session |
| object, and forwards control to the logon page if it is missing. This is |
| used to catch cases where a user has bookmarked a page in the middle of |
| your application and tries to bypass logging on, or if the user's session |
| has been timed out.</li> |
| <li><b>linkSubscription</b> - Generates a hyperlink to a details page |
| for a Subscription, which passes the required primary key values as |
| request attributes. This is used when listing the subscriptions associated |
| with a user, and providing links to edit or delete them.</li> |
| <li><b>linkUser</b> - Generates a hyperlink to a details page |
| for a User, which passes the required primary key values as |
| request attributes.</li> |
| </ul> |
| |
| <p> |
| The source code for these tags is in the <code>src/example</code> directory, |
| in package <code>org.apache.struts.example</code>, along with the other Java |
| classes that are used in this application. |
| </p> |
| </section> |
| |
| <section name="3.4.2 Page Composition With Includes" href="includes"> |
| |
| <p> |
| Creating the entire presentation of a page in one JSP file (with custom |
| tags and beans to access the required dynamic data) is a very common design |
| approach, and was employed in the example application included with Struts. |
| However, many applications require the display of multiple logically distinct |
| portions of your application together on a single page.</p> |
| |
| <p> |
| For example, a portal application might have some or all of the following |
| functional capabilities available on the portal's "home" page: |
| </p> |
| |
| <ul> |
| <li>Access to a search engine for this portal.</li> |
| <li>One or more "news feed" displays, with the topics of interest customized |
| from the user's registration profile.</li> |
| <li>Access to discussion topics related to this portal.</li> |
| <li>A "mail waiting" indicator if your portal provides free email |
| accounts.</li> |
| </ul> |
| |
| <p> |
| The development of the various segments of this site is easier if you |
| can divide up the work, and assign different developers to the different |
| segments. Then, you can use the <i>include</i> capability of JavaServer Pages |
| technology to combine the results into a single result page, or use the include tag |
| provided with Struts. There are three |
| types of <i>include</i> available, depending on when you want the combination |
| of output to occur: |
| </p> |
| |
| <ul> |
| <li>An <code><%@ include file="xxxxx" %></code> directive can include a file that contains |
| Java code or JSP tags. The code in the included file can even reference |
| variables declared earlier in the outer jsp page. The code is inlined into |
| the other JavaServer Page before it is compiled so it can definately contain more than |
| just HTML.</li> |
| <li>The include <i>action</i> (<code><jsp:include page="xxxxx" |
| flush="true" /></code>) is processed at request time, and is handled |
| transparently by the server. Among other things, that means you |
| can conditionally perform the include by nesting it within a tag |
| like <a href="../struts-logic.html#equals">equals</a> by using it's |
| parameter attribute.</li> |
| <li>The <a href="../struts-bean.html#include">bean:include</a> tag takes either a |
| an argument "forward" representing a logical name mapped to the jsp to include, |
| or the "id" argument, which represents a page context String variable to print |
| out to the jsp page.</li> |
| </ul> |
| <p> |
| Another approach to this would be to use the Struts Template Tag library. See the |
| Developer's Guide for details. |
| </p> |
| <p> |
| Tiles is an alternative to the original Template Tag library, offering several |
| enhancements and new capabilities. Tiles is available in the |
| Nightly Build, and from <a href="http://www.lifl.fr/~dumoulin/tiles/"> |
| Cedric Dumoulin's Web site</a>. |
| </p> |
| </section> |
| |
| <section name="3.4.3 Image Rendering Components" href="image_rendering"> |
| |
| <p> |
| Some applications require dynamically generated images, like the price |
| charts on a stock reporting site. Two different approaches are commonly used |
| to meet these requirements: |
| </p> |
| |
| <ul> |
| <li>Render a hyperlink with a URL that executes a servlet request. The |
| servlet will use a graphics library to render the graphical image, |
| set the content type appropriately (such as to <code>image/gif</code>), |
| and send back the bytes of that image to the browser, which will display |
| them just as if it had received a static file.</li> |
| <li>Render the HTML code necessary to download a Java applet that creates |
| the required graph. You can configure the graph by setting appropriate |
| initialization parameters for the applet in the rendered code, or you |
| can have the applet make its own connection to the server to receive |
| these parameters.</li> |
| </ul> |
| </section> |
| |
| <section name="3.4.4 Rendering Text" href="text_rendering"> |
| |
| <p> |
| Some applications require dynamically generated text or markup, |
| such as XML. If a complete page is being rendered, and can be output |
| using a PrintWriter, this is very easy to do from an Action: |
| </p> |
| <pre> |
| response.setContentType("text/plain"); // or text/xml |
| PrintWriter writer = response.getWriter(); |
| // use writer to render text |
| return(null); |
| </pre> |
| |
| <p align="center"> |
| Next: <a href="building_controller.html">Building Controller Components</a> |
| </p> |
| </section> |
| |
| </chapter> |
| </body> |
| </document> |