You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by cr...@locus.apache.org on 2000/06/03 00:26:26 UTC
cvs commit: jakarta-struts/web/documentation users_guide.html index.jsp
craigmcc 00/06/02 15:26:26
Modified: . build.xml
src/share/org/apache/struts/action ActionServlet.java
web/documentation index.jsp
Added: web/documentation users_guide.html
Log:
Add a first draft of the user's guide for Struts.
Modify the build.xml file to include generated Javadoc for the Struts
packages in the "struts-documentation.war" file.
Revision Changes Path
1.3 +16 -1 jakarta-struts/build.xml
Index: build.xml
===================================================================
RCS file: /home/cvs/jakarta-struts/build.xml,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- build.xml 2000/06/01 00:05:54 1.2
+++ build.xml 2000/06/02 22:26:25 1.3
@@ -82,6 +82,21 @@
dest="${build.home}/example/WEB-INF/${app.name}.tld"/>
</target>
+ <!-- BUILD: Create Javadoc documentation -->
+ <target name="compile.javadoc">
+ <deltree dir="${build.home}/documentation/api"/>
+ <mkdir dir="${build.home}/documentation/api"/>
+ <javadoc sourcepath="src/share"
+ destdir="${build.home}/documentation/api"
+ packagenames="org.apache.struts.*"
+ author="true"
+ private="true"
+ version="true"
+ windowtitle="Jakarta Struts API Documentation"
+ doctitle="<h1>Jakarta Struts Package</h1>"
+ bottom="Copyright © 2000 - Apache Software Foundation"/>
+ </target>
+
<!-- DIST: Construct library distributables -->
<target name="dist.library" depends="prepare.dist,compile.library">
<copyfile src="${build.home}/library/${app.name}.tld"
@@ -92,7 +107,7 @@
<!-- DIST: Construct documentation distributables -->
<target name="dist.documentation"
- depends="dist.library,compile.documentation">
+ depends="dist.library,compile.documentation,compile.javadoc">
<jar jarfile="${dist.home}/lib/${app.name}-documentation.war"
basedir="${build.home}/documentation"/>
</target>
1.2 +4 -4 jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java
Index: ActionServlet.java
===================================================================
RCS file: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ActionServlet.java 2000/05/31 22:28:11 1.1
+++ ActionServlet.java 2000/06/02 22:26:25 1.2
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v 1.1 2000/05/31 22:28:11 craigmcc Exp $
- * $Revision: 1.1 $
- * $Date: 2000/05/31 22:28:11 $
+ * $Header: /home/cvs/jakarta-struts/src/share/org/apache/struts/action/ActionServlet.java,v 1.2 2000/06/02 22:26:25 craigmcc Exp $
+ * $Revision: 1.2 $
+ * $Date: 2000/06/02 22:26:25 $
*
* ====================================================================
*
@@ -140,7 +140,7 @@
* <p>
*
* @author Craig R. McClanahan
- * @version $Revision: 1.1 $ $Date: 2000/05/31 22:28:11 $
+ * @version $Revision: 1.2 $ $Date: 2000/06/02 22:26:25 $
*/
public class ActionServlet
@@ -228,7 +228,7 @@
* containing our configuration information. [/WEB-INF/action.xml]
* <li><strong>debug</strong> - The debugging detail level for this
* servlet, which controls how much information is logged. [0]
- * <li><strong>mapping</string> - The Java class name of the ActionMapping
+ * <li><strong>mapping</strong> - The Java class name of the ActionMapping
* implementation to use [org.apache.struts.action.ActionMappingBase]
* </ul>
*
1.3 +2 -2 jakarta-struts/web/documentation/index.jsp
Index: index.jsp
===================================================================
RCS file: /home/cvs/jakarta-struts/web/documentation/index.jsp,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- index.jsp 2000/06/01 21:06:27 1.2
+++ index.jsp 2000/06/02 22:26:26 1.3
@@ -4,11 +4,11 @@
</head>
<body bgcolor="white">
-FIXME - Write the documentation and include it here!<br><br>
-
The following documentation is available:
<ul>
<li><a href="tags.html">Custom Tag Library Reference</a>
+<li><a href="users_guide.html">Struts User's Guide</a>
+<li><a href="api/index.html">Struts API Documentation</a>
</ul>
</body>
1.1 jakarta-struts/web/documentation/users_guide.html
Index: users_guide.html
===================================================================
<html>
<head>
<title>Struts User's Guide</title>
</head>
<body bgcolor="white">
<div align="center">
<h1>User's Guide: Application Design Using Struts</h2>
</div>
<h2>1. Introduction</h2>
<h3>1.1 The Model-View-Controller (MVC) Design Pattern</h3>
<h3>1.2 Mapping MVC Concepts to Struts Components</h3>
<h4>1.2.1 The Model: JavaBeans and Business Logic Classes</h4>
<h4>1.2.2 The View: JSP Pages and Presentation Components</h4>
<h4>1.2.3 The Controller: ActionServlet and ActionMapping</h4>
<h3>1.3 Designing For The Future</h3>
<h2>2. Defining Application Requirements</h2>
<h3>2.1 User Interface Requirements</h3>
<h3>2.2 Functional Processing Requirements</h3>
<h3>2.3 Applications as Conversations</h3>
<h2>3. Building the View Components</h2>
<h3>3.1 Overview</h3>
<p>Once you have defined the application requirements, work on implementing
these requirements can begin. In larger projects, many of these efforts
can proceed in parallel, because the mutual interdependencies are minimized
by the use of the MVC design pattern.</p>
<p>This chapter focuses on the task of building the <i>View</i> components
of the architecture, which will primarily be created using JavaServer Pages
(JSP) technology. In particular, the support Struts provides for building
internationalized applications, and interacting with input forms. Several
other topics related to the View components are briefly discussed.</p>
<h3>3.2 Internationalized Messages</h3>
<h4>3.2.1 Background Information</h4>
<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
of importance 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><b>MessageResources</b> - The Struts class
<code>org.apache.struts.util.MessageResources</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.
</ul>
<h4>3.2.2 Development Tasks Required</h4>
<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:
<pre>
prompt.hello=Hello
</pre>
<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:
<pre>
prompt.hello=Bonjour
</pre>
You can have resource bundle files for as many languages as you need.
</ul>
<p>When you configue 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>
<h3>3.3 Forms and FormBean Interactions</h3>
<h4>3.3.1 Background Information</h4>
<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>
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:
<pre>
<struts:text name="username"/>
</pre>
with no need to explicitly refer to the JavaBean from which the initial
value is retrieved. That is handled automatically by the framework.</p>
<h4>3.3.2 Building Forms With Struts</h4>
<p>A more 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 (from the
example application included with Struts) named <code>logon.jsp</code>:</p>
<pre>
<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts.tld" prefix="struts" %>
<html>
<head>
<title><struts:message key="logon.title"/></title>
<body bgcolor="white">
<struts:errors/>
<struts:form action="logon.do" name="logonForm"
type="org.apache.struts.example.LogonForm"/>
<table border="0" width="100%">
<tr>
<th align="right">
<struts:message key="prompt.username"/>
</th>
<td align="left">
<struts:text name="username" size="16"/>
</td>
</tr>
<tr>
<th align="right">
<struts:message key="prompt.password"/>
</th>
<td align="left">
<struts:password name="password" size="16"/>
</td>
</tr>
<tr>
<td align="right">
<struts:submit>
<struts:message key="button.submit"/>
</struts:submit>
</td>
<td align="right">
<struts:reset>
<struts:message key="button.reset"/>
</struts:reset>
</td>
</tr>
</table>
</struts:form>
</body>
</html>
</pre>
<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>struts</code> as the prefix that identifies
tags from this library, but any desired prefix can be used.</li>
<li>This page uses several occurrences of the
<a href="tags.html#message">message</a> 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 <a href="tags.html#errors">errors</a> 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 <a href="tags.html#form">form</a> 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>.
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>
<li>The <a href="tags:html#text">text</a> 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>The <a href="tags.html#password">password</a> 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 <a href="tags.html#submit">submit</a> and
<a href="tags.html#reset">reset</a> tags generate the corresponding
buttons at the bottom of the form. The text labels for each button
are created using <a href="tags.html#message">message</a> tags,
as with the prompts, so that these values are internationalized.</li>
</ul>
<h4>3.3.3 Input Field Types Supported</h4>
<p>Struts defines tags for all of the following types of input fields,
with hyperlinks to the corresponding reference information.</p>
<ul>
<li><a href="tags.html#checkbox">checkboxes</a></li>
<li><a href="tags.html#hidden">hidden</a> fields</li>
<li><a href="tags.html#password">password</a> input fields</li>
<li><a href="tags.html#radio">radio</a> buttons</li>
<li><a href="tags.html#reset">reset</a> buttons</li>
<li><a href="tags.html#select">select</a> lists with embedded</li>
<a href="tags.html#option">options</a></li>
<li><a href="tags.html#submit">submit</a> buttons</li>
<li><a href="tags.html#text">text</a> input fields</li>
<li><a href="tags.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>
<h4>3.3.4 Other Useful Presentation Tags</h4>
<p>There are several other tags in the Struts library that are useful in
creating user interfaces:</p>
<ul>
<li><a href="tags.html#enumerate">enumerate</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><a href="tags.html#getProperty">getProperty</a> retrieves the specified
property from the specified bean, and exposes it as a page scope
bean to the rest of this page. Among other things, this is a convenient
way to access a collection to be used by <code>enumerate</code>.</li>
<li><a href="tags.html#ifParameterEquals">ifParameterEquals</a> evaluates
its tag body only if a specified request parameter has a specified
value.</li>
<li><a href="tags.html#ifParameterNotEquals">ifParameterNotEquals</a>
evaluates its tag body only if a specified request parameter does not
have a specified value.</li>
<li><a href="tags.html#link">link</a> generates a hyperlink, and automatically
applies URL encoding to maintain session state in the absence of
cookie support.</li>
<li><a href="tags.html#parameter">parameter</a> renders the specified
request parameter's value, suitably filtered for characters that are
sensitive in HTML.</li>
<li><a href="tags.html#property">property</a> displays the named bean
property within a form -- use it instead of <code>text</code> for
properties that should be read only.</li>
</ul>
<h3>3.4 Other Presentation Techniques</h3>
<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>
<h4>3.4.1 Application-Specific Custom Tags</h4>
<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><code>checkLogon</code> - 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><code>linkSubscription</code> - 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><code>linkUser</code> - 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>
<h4>3.4.2 Page Composition With Includes</h4>
<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. There are two
types of <i>include</i> available, depending on when you want the combination
of output to occur:</p>
<ul>
<li>The include <i>directive</i> (<code><%@ include file="xxxxx"
%></code>) is processed when the JSP page is compiled. It is
useful when you are including HTML code that will not need to change
at request time. It treats the text being included as static text,
much like the <code>#include</code> directive in C or C++.</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="tags.html#ifParameterEquals">ifParameterEquals</a>.</li>
</ul>
<h4>3.4.3 Image Rendering Components</h4>
<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>
<h2>4. Building the Model Components</h2>
<h3>4.1 Overview</h3>
<p>The application requirements document that you produced above will likely
have focused on the user interface to be created. However, you should ensure
that the processing required for each submitted request is also clearly
defined. In general, the developer of the model components will be focusing
on the creation of Action Classes (i.e. classes that implement the
<code>Action</code> interface), supporting JavaBeans components of various
types, and deciding how to maintain the state of the application persistently
when the application is not currently operating. The Action Classes are
actually part of the Controller in a Model-View-Controller architecture, so
they are discussed in a subsequent section.</p>
<h3>4.2 JavaBeans Components</h3>
<p>The precise nature of the JavaBeans classes required by a particular
application will vary widely based on its particular requirements. However,
the following general categories of beans are often necessary.</p>
<h4>4.2.1 ActionForm Beans</h4>
<p>The Struts framework generally assumes that you have created an ActionForm
bean (that is, a Java class implementing the <code>ActionForm</code> interface)
for each input form required in your application. If you define such beans
in your <code>ActionMapping</code> configuration file (see below), the Struts
controller servlet will automatically perform the following services for you,
before calling the appropriate Action Class method:</p>
<ul>
<li>Check in the user's session for an instance of a bean of the
appropriate type, under the appropriate key.</li>
<li>If there is no such session scope bean available, a new one is
automatically created and added to the user's session.</li>
<li>For every request parameter whose name corresponds to the name
of a property in the bean, the corresponding setter method will
be called. This operates in a manner similar to the standard
JSP action <code><jsp:setProperty></code> when you use the
asterisk wildcard to select all properties.</li>
<li>The updated <code>ActionForm</code> bean will be passed to the
Action Class <code>perform()</code> method when it is called,
making these values immediately available.</li>
</ul>
<p>When you code your <code>ActionForm</code> beans, keep the following
principles in mind:</p>
<ul>
<li>Generally, there will be very little validation logic in an
<code>ActionForm</code> bean itself. This is because the purpose
of an <code>ActionForm</code> bean is to maintain the most recent
state of what the user actually typed (whether it is correct or not)
so that, in the case of detected errors, the same page can be
redisplayed exactly as the user last entered it. Then, the user
need only correct the fields that have errors, rather than typing
everything over again. (Remember, the <code>form</code> custom tag
and the associated field tags do the redisplay part for you.)</li>
<li>Define a property (with associated <code>getXxx()</code> and
<code>setXxx()</code>) methods for each field. The field name
and property name must match according to the usual JavaBeans
conventions. For example, an input field named <code>username</code>
will cause the <code>setUsername()</code> method to be called.</li>
<li>When defining String-valued properties, you might want to take special
actions if a null value is passed to a property setter method.
In the example application, attempts to set a String property to
null are changed to set a zero-length String instead. Note that
the custom tags for fields, such as <code>text</code>, deal with
null values correctly by treating them as zero-length strings,
but such conversions might be useful if you access the properties
of these beans in other ways.</li>
</ul>
<p>You should note that a "form", in the sense discussed here, does not
necessarily correspond to a single JSP page in the user interface. It is
common in many applications to have a "form" (from the user's perspective)
that extends over multiple pages. Think, for example, of the wizard style
user interface that is commonly used when installing new applications. Struts
encourages you to define a single <code>ActionForm</code> bean that contains
properties for all of the fields, no matter which page the field is actually
displayed on. Likewise, the various pages of the same form should all be
submitted to the same Action Class. If you follow these suggestions, the
page designer can rearrange the fields among the various pages, with no
changes required to the processing logic in most cases.</p>
<h4>4.2.2 Business Logic Beans</h4>
<p>You should model the basic functional logic of your application as a set
of calls to property setters of JavaBeans, followed by calls to an appropriate
method to invoke the requested logic. For maximum code re-use, these beans
should <b>not</b> know that they are being executed by a servlet.
If you find yourself having to import a <code>javax.servlet.*</code> class
in your bean, you know that you're tying yourself to servlets -- this should
be avoided.</p>
<p>Depending on the complexity and scope of your application, business logic
beans might be ordinary JavaBeans that interact with a database through JDBC
calls, or a directory server through JNDI calls. For larger applications,
these beans will often be stateful or stateless Session Enterprise JavaBeans
instead.</p>
<h3>4.3 Persistent Storage Options</h3>
<p>Many web applications will utilize a relational database (accessed through
a JDBC driver) to store the persistent data associated with the application.
Others will use Entity Enterprise JavaBeans for this purpose, which delegates
the decisions for how to maintain persistent state to the EJBs themselves.
If you are using Enterprise JavaBeans for this purpose, follow the client
design patterns described in the Enterprise JavaBeans specification.</p>
<p>For web applications based on direct database access, a common design
problem is how to make an appropriate JDBC Connection object available when
access to the underlying database is required. There are several possible
approaches to this problem -- the following rules describe one model for
dealing with this issue:</p>
<ul>
<li>Create or acquire a ConnectionPool class, which lets a set of database
connections be shared among multiple users. Struts does not (currently)
include such a class.</li>
<li>When the application is initialized, define a servlet with a load on
startup value in the application deployment descriptor. Call this the
"startup" servlet. (In most cases, there will be no need for any
requests to be processed directly by this servelt, so there would be
no <code><servlet-mapping></code> element pointing at it.)</li>
<li>In the <code>init()</code> method of the startup servlet, configure and
instantiate an instance of your ConnectionPool class, and store it as
a servlet context attribute (which is the same as an application scope
bean from the JSP perspective). It is usually convenient to configure
the connection pool based on initialization parameters passed to the
startup servlet.</li>
<li>In the <code>destroy()</code> method of the startup servlet, include
logic to gracefully release the connections that have been opened by
the connection pool. This will get called when the servlet container
shuts down this application.</li>
<li>When an Action Class needs to call a method of a business logic bean
that requires a database connection (such as "insert a new customer"),
it will perform steps like this:
<ul>
<li>Acquire the connection pool object from the servlet context
attributes.</li>
<li>Call the <code>open()</code> method of the connection pool object
to give you a connection for use within this Action Class call.</li>
<li>Call the appropriate method of your business logic bean, passing the
database connection object to be used as an argument.</li>
<li>Call the <code>close()</code> method of the allocated connection,
which will cause this connection to be returned to the pool for
later re-use on some other request.</li>
</ul>
<li>A common programming error is to forget to return the connection to the
pool, which can ultimately lead to running out of connections. Be sure
that your Action Class logic always returns the connection, even if the
business logic bean throws an exception.</li>
</ul>
<p>Following the design pattern recommended above means that you can design
your business logic classes without having to worry about how they acquire a
JDBC Connection to use -- simply include a Connection argument in any method
call that needs to access the database. When your business logic class is
utilized within a web application, it will be the responsibility of the Action
Class to allocate and release an appropriate connection. When you use the
same business logic class, for example, in a batch job, it will be
the responsibility of that application to provide an appropriate connection
(which will not need to be acquired from a pool, because most batch jobs
run in a single-threaded environment).</p>
<h2>5. Building the Controller Components</h2>
<h3>5.1 Overview</h3>
<p>Now that you have the View and Model components of your application, it is
time to focus on the Controller components. Struts includes a servlet
that implements the primary function of mapping a request URI to an Action
Class. Therefore, the primary development responsibilities related to the
Controller are:</p>
<ul>
<li>Write an Action class (that is, an implementation of the
<code>Action</code> interface) for each logical request
that may be received.</li>
<li>Write an ActionMapping class (that is, an implementation of the
<code>ActionMapping</code> interface) that defines the class
names and other information associated with each possible
mapping.</li>
<li>Write the action mapping configuration file (in XML) that is used
to configure the controller servlet.</li>
<li>Update the web application deployment descriptor file (in XML)
for your application to include the necessary Struts components.</li>
<li>Add the appropriate Struts components to your application.</li>
</ul>
<h3>5.2 Action Classes</h3>
<p>The <code>Action</code> interface defines a single method that must be
implemented by the Action Class, as follows:</p>
<pre>
public void perform(ActionServlet servlet,
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException;
</pre>
<p>The goal of the Action Class is to process this request, and generate the
corresponding response (or forward control to another component, such as a
JSP page, that will do this), just as if it were the <code>doGet()</code> or
<code>doPost()</code> method of a servlet itself. In the <i>Model 2</i>
design pattern, a typical Action Class will look like this:
<ul>
<li>Validate the current state of the user's session (for example, checking
that the user has successfully logged on). If the Action Class finds
that no logon exists, the request should be forwarded to the JSP page
that displays the username and password prompts for logging on.</li>
<li>Validate the request parameters included with this request. If the
Action Class finds a problem, it stores appropriate error messages in
a request scope bean, and forwards control back to the originating
JSP page so that the errors can be corrected.</li>
<li>Perform the processing required to deal with this request (such as
saving a row into a database). This can be done by code embedded within
the Action Class itself, or by calling appropriate methods of beans
being manipulated by the Action Class.</li>
<li>Update the server-side objects that will be used to create the next
page of the user interface (typically request scope or session scope
beans, depending on how long you need to keep these items available).</li>
<li>Forward this request (using <code>RequestDispatcher.forward()</code> to
the appropriate JSP page to create the next page of the user interface,
based on the newly updated beans.</li>
</ul>
<p>One design issue to remember as you code Action Classes is that they are
used in a multi-threaded environment. Two users who make a request to the same
Action Class at the same time will be sharing the same instance. So, an
important design rule is to not use instance variables within the Action
Class itself. This helps, because local variables (those created within the
<code>perform()</code> method), are not shared -- the JVM maintains a stack
for each active thread.</p>
<p>In addition, you want to guard against Action Classes that are too large.
This can happen when you embed your business logic in the Action Class itself,
rather than embedding it in beans that are accessed by the Action Class. It
is useful to think of Action Classes as implementing the "Adapter" pattern
in Design Patterns terminology:</p>
<ul>
<li>The Action Class knows it is accessed in a web application environment,
because it receives arguments defined by the Java Servlet API (such as
<code>HttpServletRequest</code> and <code>HttpServletResponse</code>.</li>
<li>The primary behavior of the Action Class should be to "adapt" these
servlet specific components into general JavaBeans components that do
not necessarily know they are being executed in a web application.
This is typically done by calling property setter methods on the beans,
and then invoking business logic methods as required.</li>
<li>In simple cases, the business logic itself is embedded within the Action
Classes. However, this makes maintenance and re-use of such code more
difficult. Try to limit the code in your Action Classes to translating
the servlet-specific request parameters into generic JavaBeans properties,
and managing the control flow (such as choosing which JSP page to forward
to, based on the state of the computation).</li>
</ul>
<p>The example application included with Struts stretches this design principle
somewhat, because the business logic itself is embedded in the Action Classes.
The reason for this is that the focus of the application is on illustrating the
various features of Struts. In a "real" version of this application, the logic
to maintain user subscriptions, for example, would be performed inside
JavaBeans that talk to a relational database or a directory server, or via
Enterprise JavaBeans.</p>
<h3>5.2 The ActionMapping Implementation</h3>
<p>In order to operate successfully, the Struts controller servlet needs to
know several things about how each request URI should be mapped to an
appropriate <code>Action</code> class (along with other related information).
The required knowledge has been encapsulated in a Java interface named
<code>ActionMapping</code>, which has the following properties:</p>
<ul>
<li><b>actionClass</b> - The fully qualified Java class name of the
<code>Action</code> class used for this mapping. The first time
a particular mapping is used, an instance of this class will be
created and saved for reuse later.</li>
<li><b>formAttribute</b> - The name of the session scope bean under which
the current <code>ActionForm</code> for this mapping is stored. If
this property is not defined, no <code>ActionForm</code> will be used.</li>
<li><b>formClass</b> - The fully qualified Java class name of the
<code>ActionForm</code> class used for this mapping. If you are
using the support for form beans, an instance of this class will be
created and saved automatically whenever necessary.</li>
<li><b>path</b> - The request URI path that is matched to select this
mapping. See below for examples of how matching works.</li>
</ul>
<p>Struts includes a convenient implementation of the
<code>ActionMapping</code> interface, in a class named
<code>org.apache.struts.action.ActionMappingBase</code>. If you do not need
to define any additional properties for your own mappings, feel free to use
this class as your <code>ActionMapping</code> class, as described in the
following section. However, it is also possible to define an
<code>ActionMapping</code> implementation (perhaps extending the
<code>ActionMappingBase</code> class) that contains additional properties.
The controller servlet knows how to configure these custom properties
automatically, because it uses the Struts Digester module to read the
configuration file.</p>
<p>In the example application included with Struts, this feature is used to
define two additional properties:</p>
<ul>
<li><b>failure</b> - The context-relative URI to which control should be
forwarded if the Action class detects some sort of problem with the
input fields it received. This will typically be the name of the
JSP page from which the request was sent, which will cause the form
to be redisplayed (with the error messages set by the Action Class
and the most recent input values from the ActionForm bean).</li>
<li><b>success</b> - The context-relative URI to which control should be
forwarded if the Action class successfully performs the required
function. This will typically be the name of a JSP page that prepares
the next page of the conversation flow for this application.</li>
</ul>
<p>Using these two extra properties, the Action classes in the example
application are almost totally independent of the actual names of the JSP
pages that are used by the page designers. The pages can be renamed (for
example) during a redesign, with negligible impact on the Action classes
themselves. If the names of the "next" JSP pages were hard coded into the
Action classes, they would also need to be modified.</p>
<h3>5.3 The Action Mappings Configuration File</h3>
<p>How does the controller servlet learn about the mappings you want? It
would be possible (but tedious) to write a small Java class that simply
instantiated new <code>ActionMapping</code> instances, and called all of
the appropriate setter methods. To make this process easier, Struts includes
a Digester module that is capable of reading an XML-based description of
the desired mappings, creating the appropriate objects along the way.</p>
<p>The developer's responsibility is to create an XML file named
<code>action.xml</code>, and place it in the WEB-INF directory of your
application. (Note that no DTD for this file is required, because the
actual attributes used can be different for different users.) The
outermost XML element must be <code><action-mapping></code>, and
within this element are nested zero or more <code><action></code>
elements -- one per mapping that you wish to define.</p>
<p>The <code>action.xml</code> file from the example application includes
the following mapping entry for the "log on" function, which we will use
to illustrate the requirements:</p>
<pre>
<action-mapping>
<action path="/logon"
actionClass="org.apache.struts.example.LogonAction"
formAttribute="logonForm"
formClass="org.apache.struts.example.LogonForm"
success="/mainMenu.jsp"
failure="/logon.jsp"
/>
</action-mapping>
</pre>
<p>As you can see, this mapping matches the path <code>/logon</code> (actually,
because the example application uses extension mapping, the request URI you
specify in a JSP page would end in <code>/logon.do</code>). When a request
that matches this path is received, an instance of the <code>LogonAction</code>
class will be created (the first time only) and used. The controller servlet
will look for a session scoped bean under key <code>logonForm</code>, creating
and saving a bean of the specified class if needed. The <code>success</code>
and <code>failure</code> properties indicate that the logon action should
forward control to the main menu if successful, or back to the logon form
if not successful (such as an invalid username or password).</p>
<h3>5.4 The Application Deployment Descriptor</h3>
<p>The final step in setting up the application is to configure the application
deployment descriptor (stored in file <code>WEB-INF/web.xml</code>) to include
all the Struts components that are required. Using the deployment descriptor
for the example application as a guide, we see that the following entries need
to be created or modified.</p>
<h4>5.4.1 Configure the Action Servlet Instance</h4>
<p>Add an entry defining the action servlet itself, along with the appropriate
initialization parameters. Such an entry might look like this:
<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>org.apache.struts.example.ApplicationResources</param-value>
</init-param>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/action.xml</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>2</param-value>
</init-param>
<init-param>
<param-name>mapping</param-name>
<param-value>org.apache.struts.example.ApplicationMapping</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
</pre>
<p>The initialization parameters supported by the controller servlet are
described in the <a href="api/index.html">Javadocs</a> for the
<code>ActionServlet</code> class, under the description for the
<code>init()</code> method.</p>
<h4>5.4.2 Configure the Action Servlet Mapping</h4>
<p>There are two common approaches to defining the URLs that will
be processed by the controller servlet -- prefix matching and extension
matching. An appropriate mapping entry for each approach will be
described below.</p>
<p>Prefix matching means that you want all URLs that start (after the context
path part) with a particular value to be passed to this servlet. Such an
entry might look like this:</p>
<pre>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>/execute/*</url-pattern>
</servlet-mapping>
</pre>
<p>which means that a request URI to match the <code>/logon</code> path
described earlier might look like this:
<pre>
http://www.mycompany.com/myapplication/execute/logon
</pre>
<p>where <code>/myapplication</code> is the context path under which your
application is deployed.</p>
<p>Extension mapping, on the other hand, matches request URIs to the action
servlet based on the fact that the URI ends with a period followed by a
defined set of characters. For example, the JSP processing servlet is mapped
to the <code>*.jsp</code> pattern so that it is called to process every
JSP page that is requested. To use the <code>*.do</code> extension (which
implies "do something"), the mapping entry would look like this:
<pre>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</pre>
<p>and a request URI to match the <code>/logon</code> path described
earlier might look like this:
<pre>
http://www.mycompany.com/myapplication/logon.do
</pre>
<h4>5.4.3 Configure the Struts Tag Library</h4>
<p>Next, you must add an entry defining the Struts tag library. The entry
should look like this:
<pre>
<taglib>
<taglib-uri>/WEB-INF/struts.tld</taglib-uri>
<taglib-location>/WEB-INF/struts.tld</taglib-location>
</taglib>
</pre>
<p>which tells the JSP system where to find the tag library descriptor
for this library (in your application's WEB-INF directory, instead of
out on the Internet somewhere).</p>
<h4>5.4.4 Add Struts Components To Your Application</h4>
<p>To use Struts when your application executes, you must copy the
<code>struts.tld</code> file to your <code>WEB-INF</code> directory,
and the <code>struts.jar</code> file to your <code>WEB-INF/lib</code>
directory.</p>
</body>
</html>