Sunteți pe pagina 1din 9

Mastering J2EE Application Development Series

Step 8: Designing Better User Interfaces


The Best of Both Worlds: Integrating JSF with Struts in Your J2EE
Applications
by Craig McClanahan
Learn how to add JavaServer Faces Components to Struts Applications
For several years, Struts has been a popular and widely used framework for building web applications
using Java. Recently, a new API that has significant overlap with Struts functionalityJavaServer Faces
(JSF)has become standard, giving rise to questions about which technology developers should use,
and what they can do with existing Struts-based applications to start taking advantage of JSF's
capabilities. This article briefly introduces both technologies, and discusses how to migrate the user-
interface elements from Struts to JSF, providing a technique you can use to integrate the two
technologies to obtain the best of both worlds.
"As the Struts
framework has
evolved, its
developers
have strongly
favored API
stability."
Benefits of the Struts Framework
The Struts Framework is a very popular framework for building web applications in Java. Its key
features include:
G An overall architecture based on Model-View-Controller (MVC) design principles in which
all requests get funneled through a controller that exerts overall management and
dispatches requests to appropriate application components as needed, based on logical
identifiers that reduce coupling between tiers.
G Form-management capabilities, such as the ActionForm JavaBean that represents the server side state of the input
fields on a form, and a validation framework externaliz the configuration of the set of correctness checks to be applied
to input field values, plus implement those checks on both the client side and the server side.
G The Tiles framework for layout management, which supports creation of sophisticated layout templates that can be
reused across multiple pages, and thus allows easy modifications to the overall look and feel of an application.
G A set of JSP custom tags that can simplify the process of creating the application's HTML markup for the view tier of
your application, and which works in a synergistic way with the form management capabilities and the overall
controller architecture.
This combination of features plus the maturity of the Struts implementation (originally created in 2000), and the substantial
supporting ecosystem around Struts (documentation, books, articles, consultants, support forums, trained developers, and
tools support) are some of the reasons Struts has become a de facto web application architecture for J2EE developers.
The Road Ahead for Struts
As the Struts framework has evolved, its developers (including myself) have strongly favored API stability over other goals, to
ensure that porting Struts applications from earlier versions would be easy and not require developers to make significant
changes to their code. The last two major feature release transitions from 1.0 to 1.1, and from 1.1 to 1.2) are evidence of that
goal, which remains a primary emphasis of the current effort towards Struts version 1.3: the development focus has been on
remodeling the insides of Struts to make it easier to customize and use, while retaining backwards compatible APIs for
existing applications so that developers wanting to can easily transition to the newer version.
That said, down the road, future development of Struts must take into account two major factors:
G Over the past four years, many innovations in web application frameworks have been implemented, offering elegance
in some areas that Struts has not been able to match given our commitment to backwards compatibility.
G In the last year, JavaServer Faces, a standard Java API for building user interface components for web
applicationsessentially a framework with substantial overlap with Strutswas released.
For these reasons, beyond the ongoing work on version 1.3 of Struts, its developers have also started conversations about
what a version 2.0 of Struts might look likethe major version number change indicating that we'd be willing to focus more
on bringing the design of Struts up to date with current technology trends, and less on backwards compatibility.
In fact, I have made one particular proposal (code named "Shale") that envisions a Struts 2.0 that is built around JavaServer
Faces, which provides value added features that JavaServer Faces by itself does not provide. (For more information about
Shale, start at http://wiki.apache.org/struts/StrutsShale.) Let's look a bit at some of the benefits of JavaServer Faces before
getting into how to bridge the two technologies in your existing Struts-based J2EE applications.
Benefits of JavaServer Faces
As just noted above, JavaServer Faces is the standard Java API for building user interface components in web applications.
It focuses on the view tier of a Model-View-Controller architecture, while providing enough controller capability to write simple
to moderately complex applications using this API alone. Its key features include:
G Fundamental APIs for user interface components, plus a basic set of standard components that are guaranteed to
exist in any implementation of JavaServer Faces.
G Event- and listener-model for handling server side events, based on the standard JavaBeans design patterns.
G Value-binding and method-binding-expressions based on a superset of the expression language introduced in the
JSP Standard Tag Library (JSTL) 1.0, and incorporated into JavaServer Pages (JSP) 2.0. These expressions let you
bind component properties to objects in your data model and or event handling methods to your business logic,
without requiring the components to have any detailed knowledge of the Java classes involved.
G Well defined request processing lifecycle that implements the Front Controller design pattern (the same pattern
implemented in the Struts controller), with plug in locations for application logic that can respond to events occurring
during the processing of each request.
G Basic page navigation support, with a default implementation that chooses the next view (or page) based on three
factors:
H The view that is currently processing this request.
H The action method that was invoked (typically, each action method corresponds to a submit button on a form).
H The logical "outcome" string returned by the invoked action method that describes the results of this action.
G Managed beans facility that, in the process of evaluating value binding and method binding expressions, can cause
new beans to be instantiated on demand, have their properties configured, and optionally stored into some scope.
The managed beans facility implements the style of Inversion of Control (IoC) configuration known as "setter injection".
The Road Ahead for JSF
Initially released in March 2004, JavaServer Faces 1.0 was soon followed by a version 1.1 maintenance release that cleaned-
up some typographical errors and inconsistencies in the initial version, and also fixed several bugs in the corresponding
reference implementation.
JavaServer Faces 1.2 is currently in development (under the auspices of the JSR-252 expert group). Most of the
development effort is focused on improving the alignment between JavaServer Faces and JavaServer Pages (version 2.1 of
which is also under development), particularly in the areas of resolving differences in the expression language syntax and
semantics, and interoperability issues between JavaServer Faces components and JSP template text.
"We'd be
willing to focus
more on
bringing the
design of
Struts up to
date with
current
technology
trends, and
less on
backwards
compatibility."
When complete, JavaServer Faces 1.2 support will be required in any Java 2 Enterprise Edition
(J2EE) 5.0 platform: applications based on J2EE 5.0 will be able to assume that the application
server supports JSF. In the mean time, JavaServer Faces has already gained substantial adoption
by developers (including those who are creating custom component libraries based on the
standard APIs), as well as robust support in tools such as Oracle JDeveloper 10g, Sun Java
Studio Creator, and IBM WebSphere Application Developer. It is clear that this technology will
become even more widely adopted in the future.
Which Technology Should I Use?
When one technology standardizes in a functional area that overlaps an existing de facto
standard, as in this case, with JavaServer Faces and Strutsdevelopers and architects naturally
want advice about which of the two technologies to useor, in fact, whether they can or should be
used together. I addressed this question at length in a blog entry recently.
Leaving that question to the blogosphere, let's assume you have one or more existing applications
based on Struts. You see the potential for using some of the sophisticated JavaServer Faces
components becoming available to enhance the user interface of your application, but you do not have time to completely
rewrite the application based on JavaServer Faces APIs. Is there any way that you can have the best of both worlds, using
the new user interface components while preserving your investment in business logic, validation, and all the rest?
The answer is "yes," by using the Struts-Faces integration library created expressly for this purpose. The primary goal of this
library is to let developers of existing applications migrate user-interface components from Struts to JSF, one page at a time,
with minimal changes to existing struts-config.xml files and without any changes to the back-end business and persistence
logic.
The library works with Struts 1.1 or the more recent Struts 1.2.x. A final release of the library is expected soon, but in the
meantime, nightly builds are available.
Note that JavaServer Faces requires a platform that supports Servlet 2.3 (or later) and JSP 1.2 (or later), both of which are
supported by any J2EE 1.3 (or later) platform.
Getting started with the Struts-Faces Integration Library
Let's go through a simple example. First, download the Struts-Faces Integration Library, and follow the instructions in the
README.txt file to set up your build environment to incorporate the new library in your application.
To understand the migration process, let's look at an example JSP page that defines the logon screen for your application.
The current Struts-based version might look something like this:
Listing 1: A simple Struts-based logon JSP
<%@ taglib uri="/tags/struts-bean" prefix="bean" %>
<%@ taglib uri="/tags/struts-html" prefix="html" %>
<html:html>
<head>
<title><bean:message key="logon.title"/></title>
</head>
<body>
<html:errors/>
<html:form action="/logon"/>
<table border="0">
<tr>
<td align="right">
<bean:message key="prompt.username"/>
</td>
<td align="left">
<html:text property="username"/>
</td>
</tr>
<tr>
<td align="right">
<bean:message key="prompt.password"/>
</td>
<td align="left">
<html:password property="password"/>
</td>
</tr>
<tr>
<td align="right">
<html:submit value="Log On"/>
</td>
<td align="left">
<html:reset/>
</td>
</tr>
</table>
</html:form>
</body>
</html:html>
In the next several steps, you'll see that there are several simple modifications that need to be made to use the JSF tag
libraries, to change how the page handles localization for messages, and other such details.
Step 1: Change the tag library declarations Replace the tag library declarations at the top of the page (and change the
<html:html> tag to a plain <html> element) with the following declarations:
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://struts.apache.org/tags-faces" prefix="s" %>
<f:view>
<html>
The first two tag libraries are the standard ones provided by any JavaServer Faces implementation. The third is the
integration library that contains tags specifically designed to make migration easier. See the tag library documentation
included in the distribution for more details.
Be sure to also, replace the </html:html> element at the end of the page with </html> , and add the closing </f:view> tag.
Step 2: Modify declarations for localized messages The original Struts page in Listing 1 follows best practices and uses
the <bean:message> tag to support localization of the page title and the field prompts. To enable localized messages in the
migrated page, add the following declaration immediately below the new <f:view> element:
<f:loadBundle var="messages" basename="com.mycompany.myapp.ApplicationResources"/>
Replace the specified basename attribute with the name of the resource bundle containing your application resources for this
page. The tag will then make messages available within this page, under the name messages.
Next, replace each use of the <bean:message> tag with a <h:outputText> component. For example, the page title would be
specified as:
<title>
<h:outputText value="#{messages['logon.title']"/>
</title>
This instructs JavaServer Faces to look up a message stored under key logon.title in your application resources. The
response will be localized based on the Locale selected for this user.
Step 3: Change tags for error and form components JavaServer Faces components cannot read Struts-provided
ActionError and ActionMessage messages; nor can its form component automatically load an ActionForm bean (as does the
standard Struts form tag). That's why the integration library provides specialized components to support these functions in the
way expected by Struts application. To use these components, replace the <html:errors/> and <html:form> tags with:
<s:errors/>
<s:form action="/logon">
Don't forget to change the closing </html:form> so that it reads </s:form> instead.
"In a JSF-and-
Struts
integrated
application,
JSF
components
handle the
purely visually-
oriented HTTP
requests, while
business
transaction
events go
through the
standard Struts-
request-
processing
lifecycle"
Step 4: Using JSF EL for input fields Each input field in a Struts form is tied to a property in your
form bean. To accomplish the same thing with the JavaServer Faces components, we use value
binding expressions. Since JavaServer Faces does not know how to look up a form bean
definition, we must reference them explicitly in the expressions. For example, assuming that the
form bean name (registered in struts-config.xml) is logonForm, you would replace the <html:text>
and <html:password> tags with:
<h:inputText id="username" value="#{logonForm.username}"/>
...
<h:inputSecret id="password" value="#{logonForm.password}"/>
Step 5: Change tags for submit and reset buttons The last change we need to make to the
original JSP in Listing 1 is to replace the two button tags with their corresponding JavaServer
Faces versions:
<h:commandButton id="submit" type="SUBMIT"
value="#{messages['button.logon']"/>
...
<h:commandButton id="reset" type="RESET"
value="#{messages['button.reset']"/>
Note that JavaServer Faces allows us to localize the button labels using the same mechanism that
we used for field prompts earlier. (Be sure to define the properties in your resource bundle for the
button.logon and button.reset keys, otherwise this won't work.) Listing 2 shows the JSP with all these changes made. But
there's still one more change to make to the infrastructure of your application server.
Listing 2: Example logon JSP after migration using the Struts-Faces Integration Library
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://struts.apache.org/tags-faces" prefix="s" %>
<f:view>
<f:loadBundle var="messages" basename="com.mycompany.myapp.ApplicationResources"/>
<html>
<title><h:outputText value="#{messages['logon.title']"/></title>
</head>
<body>
<s:errors/>
<s:form action="/logon"/>
<table border="0">
<tr>
<td align="right">
<h:outputText value="{messages['prompt.username']"/>
</td>
<td align="left">
<html:text property="username"/>
</td>
</tr>
<tr>
<td align="right">
<h:outputText value="#{messages['prompt.password']"/>
</td>
<td align="left">
<h:inputSecret id="password" value="#{logonForm.password}"/>
</td>
</tr>
<tr>
<td align="right">
<h:commandButton id="submit" type="SUBMIT" value="#{messages['button.logon']"/>
</td>
<td align="left">
<h:commandButton id="reset" type="RESET" value="#{messages['button.reset']"/>
</td>
</tr>
</table>
</s:form>
</body>
</html>
</f:view>
Step 6: Changes to the web application deployment descriptor Before your migrated page can actually work, you must
modify the configuration files to refer to the faces resources rather than the JSPs. In struts-config.xml, change any logical
forward pointing at /logon.jsp to /logon.faces instead, and add the JavaServer Faces servlet and servlet mapping declarations
to your web.xml file (in the appropriate places):
<servlet>
<servlet-name>faces</servlet-name>
<servlet-class>
javax.faces.webapp.FacesServlet
<servlet-class>
</servlet>
...
<servlet-mapping>
<servlet-name>faces</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
These settings tell your servlet container to forward any request URL that ends with .faces to the JavaServer Faces request
processing lifecycle.
At runtime, the Struts-Faces Integration Library will customize that lifecycle (using standard extension points provided by
JavaServer Faces) such that JavaServer Faces will process all user interface oriented events (such as expanding or
contracting a node in a tree control), but form submits will be forwarded to the standard Struts request processor, which will
perform the usual Struts functionality, such as performing server side validation, invoking the correct action, and navigating to
the correct forward.
Begin Testing
None of the form beans or actions must be modified, so we can now go ahead and simply test this page for correct operation.
When you are through with this page, go on to the next page. Or simply migrate and deploy only the most important pages, if
you don't have time to do them all at once.
Conclusion
As you have seen from this simple example, taking advantage of the capabilities of JavaServer Faces components while
maintaining your investment in the model tier and business logic functionality of existing applications is straightforward. In a
JSF-and-Struts integrated application, JSF components handle the purely visually-oriented HTTP requestsfor example,
clicking a tree control node to expand its contentswhile business transaction events go through the standard Struts-request-
processing lifecycle.
In this modified application, you are not leveraging the controller capabilities provided by JavaServer Faces, since you are
continuing to use those facilities in Struts. It's technically feasible to migrate the back-end processing from a Struts based
architecture to a JavaServer Faces architecture as welland this is a reasonable strategy if you want to minimize the number
of different frameworks used in your application. Nonetheless, such a transition will be simpler if the view tier's pages are
migrated first, as done in this article.
Next Steps
Oracle JDeveloper embraces popular open source frameworks and tools, providing built-in features for Struts, Ant, JUnit,
and CVS. Such integration enables developers to use these open source tools to streamline their development process.
For example, Oracle JDeveloper provides a Struts page flow modelera visual approach that simplifies the development
of the application flow. Developers model page flows by simply dragging and dropping Struts components onto a
diagram that is automatically synchronized with the source in the struts-config.xml file. As another example, Oracle ADF
uses the Struts controller to manage the flow of Web applications.
Figure: Oracle JDeveloper Visual Struts Page Flow Diagram

Download Oracle JDeveloper 10g (10.1.3) Developer Preview
Here are some additional resources:
G Apache Struts, Tiles and ADF
G Using Struts 1.2.1 with JDeveloper 10g
G Suppressing the Struts Page Flow Diagram
G Building a Web Store with Struts & ADF Frameworks
G Controlling Logging in Struts Based Applications
G Online Demo - Introduction to Struts Visual Page Flow
G Developing a J2EE Application using TopLink, Struts, JSP and ADF Databinding
G Adding a BI Beans Graph in an ADF Business Components/JSP/Struts Application
G Creating an Input Form JSP Page Using the Struts Validator to Validate Data Entry
G Building a Simple JSF and Toplink App in JDeveloper 10.1.3 Preview
Craig McClanahan is a Senior Staff Engineer at Sun Microsystems, Inc. He is presently architect for the team that is building
Sun Java Studio Creator, an IDE for graphically assembling web applications. Craig is also the original creator of Struts.
Copyright 2005, Oracle. All Rights Reserved.

S-ar putea să vă placă și