|
Building a Web Store with Struts & ADF Frameworks
Building a Web
Store with Struts & ADF Frameworks
JDeveloper 10g Release
10.1.2 Version Author: Steve Muench, Oracle ADF Development Team Contributions from Tony JewtshenkoDate: May 4, 2005
Abstract
By
exploring the details of a sample application built using two popular
off-the-shelf J2EE frameworks, Apache Struts and Oracle ADF, this paper
illustrates how developers can build J2EE-compliant applications with maximum
developer productivity using a framework-based approach. In the process, it
highlights the full lifecycle support that the Oracle JDeveloper 10g IDE
provides for framework-based development using Struts and ADF.
| NOTE: |
This version of the ADF Toy
Store Demo is designed to be used with JDeveloper 10g, release 10.1.2. If you
are familiar with the previous version of the demo for JDeveloper 9.0.5.2, you
might want to skip to the Overview of
Changes from ADF Toy Store 9.0.5.2 Version section. You
need to re-run the supplied Toystore.sql database setup
script due to changes in the underlying stored procedures the demo is now
using.
|
| NOTE: |
This article complements the
ADF
Data Binding Primer and ADF/Struts Overview [1] whitepaper by explaining
the implementation details of a complete application built using Oracle ADF and
Apache Struts. The present article provides an overview of the concepts
necessary to understand the web store demo implementation, but please see this
other whitepaper for additional information on the underlying features. In
addition, the
JDeveloper
10g and Oracle ADF Online Documentation [2],
JDeveloper 10g
Tutorials [3],
JDeveloper 10g
Samples [4] are great resources to be aware of, too, as are the related
whitepapers
ADF
Business Components Benefits in a Nutshell [5],
ADF
Business Components J2EE Design Pattern Catalog [6], and
Most
Commonly Used Methods in ADF Business Components [7].
While
this document should print fine in Internet Explorer, if you prefer, a
PDF
version of this paper [8] is also available.
|
Contents Lessons from the Past Advice
for the Future Rebuilding a Web Storefront with Struts and ADF Demo Installation and
Setup Quick Tour Through the Demo Browsing Products and Adding Them to Your
Cart Checking Out and Signing In Register a New User and Editing an
Existing User's Profile Trying Out the Demo in Another
Language Dissecting the Demo How the Application is Organized Into Packages and Projects Advantages of a Model/View/Controller
Architecture Implementing the Model Layer Using ADF
Business Components Testing
Business Tier Components with JUnit Implementing the Controller
Layer with the Apache Struts Framework Understanding ADF/Struts Integration Building the View Layer with
JSP Pages and JSTL Struts and ADF Features for Building
Multilingual Applications Using ADF, XSQL Pages, XSLT, and XML Schema Together Implementing the View Layer Using ADF
UIX Customizing the Default Framework
Behavior Additional
Points of Interest Around the Demo Deployment and
Packaging Considerations Getting Started on
Your Own ADF-Based Applications Conclusion Overview of
Changes from ADF Toy Store 9.0.5.2 Version Database Setup Controller Layer Changes Changes to Improve Performance
& Scalability JSP Web Tier Changes Added new ADF UIX View Layer Bugs Fixed Related Documents Appendix 1: Known Issues Appendix 2: Configuring Toy Store Datasources on Apache
Tomcat
Lessons from the Past
The initial release of Sun's
Java
Pet Store Demo [9] was a watershed event. Thirsty for guidance on
implementing real-world J2EE applications, Java developers dove into its cool
pools of code like parched creatures of the Kalahari. But after exploring the
depths of its refreshing routines, many returned to the surface wondering why
application infrastructure code dominated the demo.
Obscured by repetitive implementations of J2EE design patterns, the more
interesting business functionality of the web storefront
was hard to find.
On further analysis, one point was clear to
developers: for their own applications they would need to
reimplement the same design pattern drudgery. Common sense
dictated a framework approach, but developers would have to decide whether to
build their own or leverage existing ones. To make a more informed decision,
they read books like Core J2EE Patterns: Best
Practices and Design Strategies which gave the design patterns names,
organized them into functional layers, and explained how a typical J2EE
application should use
fifteen key patterns [10] together.
Another book, EJB Design Patterns: Advanced Patterns,
Processes, and Idioms, came with a handy poster in back, detailing
twenty-one design pattern tips and diagrams for easy cubicle-wall reference.
These and other resources clarified that correctly and efficiently coding all
these patterns from scratch would be no trivial task.
While their
instincts undoubtedly warned them otherwise, many developers opted anyway for
the "do-it-yourself" approach on their first J2EE application projects. A year
later, many were still struggling to deliver feature-complete, well-performing
applications.
Advice
for the Future
On the opening page of his book
Expert One-on-One: J2EE Design and Development
(Wrox Press), Rod Johnson offers an observation on this phenomenon:
The return on investment for many J2EE projects is
disappointing. Delivered systems are too often slow and unduly complex.
Development time is often disproportionate to the complexity of business
requirements.
Why? Not so much because of the shortcomings of J2EE
as because J2EE is often used badly. This often results from approaches to
architecture and development that ignore real world problems. A major
contributing factor is the emphasis in many J2EE publications on the J2EE
specifications rather than the real world problems people use them to address.
Many issues that commonly arise in real applications are simply ignored.
Throughout the rest of his book, Rod debunks many
myths about J2EE development and offers pragmatic guidance about which J2EE
technologies to use under what circumstances. On page 166, he begins a section
on frameworks and how they can help:
Many common
problems (beyond those addressed by J2EE application servers) have been solved
well by open source or commercial packages and frameworks. In such cases,
designing and implementing a proprietary solution may be wasted effort. By
adopting an existing solution, we are free to devote all our effort to meeting
business requirements.
After commenting that existing
frameworks can mean a slightly steeper learning curve, Rod later motivates why
this trade-off is worthwhile to gain a strong application infrastructure. On
page 395, he clearly explains the benefits:
Using a
strong standard infrastructure can deliver better applications, faster. A
strong infrastructure makes this possible by achieving the following
goals:
- Allowing application code to
concentrate on implementing business logic and other application functionality
with a minimum of distraction. This reduces time to market by reducing
development effort, and reduces costs throughout the project lifecycle by
making application code more maintainable (because it is simpler and focused on
the problem domain). This is the ultimate goal, which many of the following
goals help us to achieve.
- Separating
configuration from Java code
- Facilitating the
use of OO design by eliminating the need for common
compromises.
- Eliminating code duplication, by
solving each problem only once. Once we have a good solution for a problem such
as a complex API we should always use that solution, in whatever components or
classes that encounter the problem
- Concealing
the complexity of J2EE APIs. We've already seen this with JDBC; other APIs that
are candidate for a higher-level of abstraction include JNDI and EJB
access
- Ensuring correct error handling. We
saw the importance of this when working with JDBC in Chapter
9.
- Facilitating internationalization if
required.
- Enhancing productivity without
compromising architectural principles. Without adequate infrastructure, it is
tempting to cut corners by adopting quick, hacky solutions that will cause
ongoing problems. Appropriate infrastructure should encourage and facilitate
the application of sound design principles.
- Achieving consistency between applications within an organization. If all
applications use the same infrastructure as well as the same application server
and underlying technologies, productivity will be maximized, teamwork more
effective, and risk reduced.
- Ensuring that
applications are easy to test. Where possible, a framework should allow
application code to be tested without deployment on an application
server.
Several existing
application frameworks provide ready-to-use implementations of the kind of
strong application infrastructure that Rod recommends. If you use
these frameworks, you won't have to design, code, debug,
and maintain your own infrastructure code.
In this whitepaper, we
examine two existing J2EE frameworks by studying a working sample application.
By patterning the sample application after the "classic" Java Pet Store Demo,
we've made it easier for readers familiar with the original demo to compare the
developer productivity that a framework-based J2EE development approach can
provide.
Rebuilding a Web Storefront with Struts and ADF
The ADF Toy
Store demo is a simple web storefront application adhering to the
Model/View/Controller (MVC) design pattern. It is implemented using two
existing J2EE application frameworks:
Apache Struts [11] and
Oracle
Application Development Framework [12] (ADF). Both the Struts and ADF
frameworks have been iteratively developed to support the requirements of
communities of application developers building real-world applications. Many
aspects of their design and implementation echo the pragmatic suggestions that
Rod Johnson details throughout his book.
As with all MVC-style web
applications, the ADF Toy Store has the basic architecture illustrated in
Figure 1:
- The
model layer represents the business information needed by
the application,
- The controller
layer handles user input, interfaces with the model layer, and picks
the presentation
- The view
layer presents the model data to the
end-user.
The model layer consists of one
or more business services that expose application
functionality and access to model data through a business
service interface that is easy to test. These business services, in turn, rely
on query components to retrieve that data and on
business objects to validate and persist any new or
modified data. Code implementing the business delegate
design pattern abstracts the details of locating and using the business
services. When JavaServer pages are used for the view layer along with a
cleanly separated controller layer, many J2EE books refer
to the architecture, shown in Figure 1, as a best practices
"JSP Model 2" architecture. The number "2" is used because this MVC-based
architecture for JSP is an evolution over first-generation JSP-based
approaches.
 Figure 1: Best Practices "JSP Model 2"
MVC Web Application Architecture
By
dissecting the framework-based implementation of our ADF Toy Store demo, we'll
learn how ADF simplifies building all aspects of the model layer, and how the
Struts and ADF frameworks cooperate to simplify implementing the view and
controller layers. In the process, we'll also see plenty of evidence for how
Oracle JDeveloper 10g provides a productive environment covering the full
development lifecycle for building these kinds of MVC-style business
applications.
Before diving into the explanation of the demo, let's
make sure you can open and run the demo in JDeveloper 10g. The next section
details the steps to get the demo setup correctly on your
system.
Demo Installation and
Setup
These instructions assume that you are running
Oracle JDeveloper 10g [13]
production, version 10.1.2. The demo will not work with earlier versions of
JDeveloper.
We also assume that you have access to an Oracle
database, and privileges to create new user accounts to setup the sample
data.
| NOTE: |
ADF is designed to work with any relational database,
and has been tested with Oracle, Oracle Lite, DB2, and SQLServer. The
Using
BC4J with Foreign Datasources [14] whitepaper covers the details (which are
still valid for Oracle ADF as well), but to make the demo explanation easier to
follow, herein we've made the simplifying assumption that you're using the
Oracle database, version 8.1.7 or later.
|
- Download the
adftoystore_10_1_2.zip [15]
file if you haven't already.
-
Extract the
contents of the adftoystore_10_1_2.zip file with the
standard JDK jar utility into a convenient directory.
jar xvf adftoystore_10_1_2.zip
This will create a directory
adftoystore, and subdirectories. These instructions assume
you've extracted the adftoystore.zip file into the root
directory C:\ thus ending up with a demo "root" directory of
C:\adftoystore.
| NOTE: |
If the
jar command does not work on your system, double-check that
you have included the JDKHOME/bin
subdirectory in your system path. If you downloaded the full version of Oracle
JDeveloper 10g, then it comes with a 1.4.2 JDK in the
JDEVHOME/jdk directory. |
-
Create the TOYSTORE and
TOYSTORE_STATEMGMT user accounts in the database using the
provided SQL script.
Run the SQL script
./adftoystore/DatabaseSetup/CreateToyStoreUsers.sql like
this:
cd C:\adftoystore\DatabaseSetup
sqlplus /nolog @CreateToyStoreUsers.sql
After entering your SYS account's
password, the script will create the TOYSTORE and
TOYSTORE_STATEMGMT user accounts. The
TOYSTORE schema will contain the ADF Toy Store application
tables, while the TOYSTORE_STATEMGMT schema will be used by
the ADF state management facility (described later in this whitepaper) to store
pending data across web pages.
-
Create the
application tables for the ADF Toy Store demo, along with some sample
data.
Run the SQL script
./adftoystore/DatabaseSetup/ToyStore.sql like this:
sqlplus toystore/toystore @ToyStore.sql
| NOTE: |
If you have a version of the Oracle database
prior to Oracle 10g, the command purge
recyclebin at the end of this script will give an error. It's
harmless and you can just ignore it. |
-
Setup two database connections in the JDeveloper 10g IDE corresponding to
the two database accounts we created above.
Define connections in
the JDeveloper 10g IDE named...
toystore, corresponding to the TOYSTORE
user (password TOYSTORE) and
toystore_statemgmt corresponding to the
TOYSTORE_STATEMGMT user (password
TOYSTORE).
| NOTE: |
The
two connection names are case-sensitive and should be
typed in lowercase as shown. |
To save some typing, you can
import these two connections from the supplied
jdev_toystore_connections.xml file in the
./adftoystore/DatabaseSetup directory. To do so, select the
Database category folder in the Connections Navigator and
choose Import Connections... from the right-mouse
menu. Supply the jdev_toystore_connections.xml file name as
the file to import from. After importing the two named connections, you should
test each connection by selecting it, double-clicking to bring up the
Connection Wizard, and visiting the
Test tab. If clicking on the Test
Connection button does not yield a "Success!" message, then correct
the connection details on the Connection tab to work for
the database to which you want to connect. By default, the connections are
defined against a database on your local machine listening on port
1521 with a SID of
ORCL.
-
Insure that the
JUnit Extension for JDeveloper is installed.
JUnit [16] is the defacto standard tool
for building regression tests for Java applications. Oracle JDeveloper 10g
features native support for creating and running JUnit tests, but this feature
is installed as a separately-downloadable IDE extension. You can tell if you
already have the JUnit Extension installed by selecting File |
New... from the JDeveloper main menu, and verifying that you have
a Unit Tests (JUnit) subcategory under the
General top-level category in the New
Gallery.
If you do not already have the JUnit
extension installed, then download it from
here [17]. You'll find
it along with all the other extensions available for JDeveloper in the
JDeveloper
Extension Exchange [18] on OTN. To complete the installation of the
extension, first exit from JDeveloper if you are currently running it. With
JDeveloper not running, extract the contents of the
downloaded zip file into the ./jdev/lib/ext subdirectory
under your JDeveloper installation home directory. Then, restart
JDeveloper.
Finally, you should verify that the
junit3.8.1 subdirectory exists in your JDeveloper
installation home. This directory will automatically get created the first time
you run any JUnit wizard from the Unit Tests (JUnit)
category of the New Gallery. However if you don't plan on creating any JUnit
tests yourself yet, you can do the following steps to make sure the directory
gets setup correctly. Assuming your current directory is the JDeveloper
installation home directory...
-
jar
xvf jdev/lib/ext/junit_addin.jar junit3.8.1.zip
This
extracts the junit3.8.1.zip file from the
junit_addin.jar archive. This zip file contains the
distribution of JUnit with which JDeveloper has been tested.
-
jar xvf junit3.8.1.zip
This
extracts the contents of the junit3.8.1.zip file into the
JDeveloper installation home
directory.
- Open the
./adftoystore/ADFToyStore.jws workspace in JDeveloper
10g
-
Run the application inside the JDeveloper
10g IDE by running the index.jsp page in the
ToyStoreViewController.jpr project as shown in
Figure 2.
 Figure 2: Running
the ADF Toy Store Application Inside JDeveloper 10g
| NOTE: |
Since
index.jsp is configured as the Default Run
Target on the Runner panel of the project
properties for the ToyStoreViewController project, you can
also simply click the Run icon in the IDE toolbar when this project is active
to run the application, or pick the Run menu item on the
ToyStoreViewController project's right-mouse menu. You can
see the project properties by clicking on it in the Navigator and selecting
Property Properties... from the right-mouse
menu. |
Running the index.jsp page from
inside JDeveloper will startup the embedded Oracle Application Server 10g
Oracle Containers for J2EE (OC4J) server, launch your default browser, and
cause it to request the URL:
http://yourmachine:8988/ADFToyStore/index.jsp
If everything is working correctly, you will see the
home page of the ADF Toy Store demo, as shown in Figure 3.
| NOTE: |
If following the steps above didn't produce the above demo
home page as expected, see Appendix 1 for a list of known
issues and troubleshooting tips. |
 Figure 3: ADF
Toy Store Demo Home Page
| NOTE: |
After exploring
the demo using the embedded Oracle Containers for J2EE (OC4J) instance that is
built-in to JDeveloper 10g, if you want to install the demo on an external OC4J
instance, Oracle Application Server, Tomcat, or other supported server see
Deployment and
Packaging Considerations |
Quick Tour Through the Demo
Before we
dive into explaining how the demo was built, let's begin with a quick overview
of the end-user functionality of our web storefront application.
Browsing Products and Adding Them to Your
Cart
The ADF Toy Store is a fictitious online store that sells
toys. The products for sale are organized into five categories: Accessories,
Games, Party Supplies, Toys, and Models. From the home page, you can browse
products in the store in two ways:
- Selecting a category name to see the products in that category,
or
- Using the What are you looking
for? search box in the banner to find products by name, regardless
of what category they belong to.
If the
list contains more than three products, they are presented a page at a time.
You can use the Next or Previous
links that appear above the item list to browse through the complete
list.
Clicking on the name of a product shows you a list of the
different product items for sale. For example, clicking on the name of a
product like Pinata, you will see a list of the different
kinds of piñatas that are available as shown in
Figure 4.
 Figure 4: Browsing Different Kinds of Items for a Product Type
To see a
detailed description and a picture of any product, just click on its
name.
On any page where the
button appears, you can click
on it to add one of those items to your shopping cart.
You can see
what items you have in your shopping cart at any time by clicking on the
button, which shows a page listing the
items and quantities you have selected so far, as shown in
Figure 5.
 Figure 5: Shopping Cart
Display
To adjust the quantities of the items in the
cart, just type over the current value in the Quantity
field for one or more items, and click the
button to see the recalculated
shopping cart total. You can remove an item from your cart either by clicking
the button, or by adjusting the
item to have a zero quantity.
Checking Out and Signing In
From the Shopping Cart page,
by clicking on the button you
can proceed to the Review Checkout page. From there, you can review your
purchase and if you are happy with it, press the
button to continue.
If
you have not already signed into the Toy Store as a registered user, you will
be prompted to sign in at this point to continue with the checkout process. The
sign in page looks like what you see in Figure 6. The user
named j2ee is already registered, with a password of
j2ee, so you can provide these credentials to
continue.
| NOTE: |
If instead you want to register as a new user, you
can click the Register as New User link. See the next
section for details...
|
 Figure 6: ADF Toy
Store Sign-in Page
After successfully signing in, you will proceed to the page where you can
confirm your shipping and payment details. Here, to see some of the application
validation logic that's implemented in the demo, you can try:
- Entering an invalid state abbreviation of
ZA for the country USA
- Entering a credit card number that is not comprised of 16
digits
and pressing the
button. You should see the multiple
validation errors as shown in Figure 7 .
 Figure 7: Shipping Information Validation Errors On Form
Submission
After fixing
those errors by entering a valid state abbreviation like CA, and filling out a
full 16-digit credit card number, try causing some additional validation errors
by:
- Entering a date in the past for the
expiration date of your credit card
- Blanking
out a required field like Last Name.
You
should again see the relevant set of remaining validation errors that need to
be corrected when you press the
button again as shown in Figure 8.
 Figure 8: Additional Shipping Information Validation Errors
| NOTE: |
When you submit this web page, without having to write any code, the data
is automatically communicated to the underlying business objects, which in
turn, enforce their declarative business rules. These rules get enforced by
your ADF-powered business components as part of normal operation, and work
consistently with any kind of user interface technology. Rather than simply
presenting the first error that is raised, ADF allows you to easily present the
user with a maximal set of errors that have been flagged in a single
round-trip, so the user can fix all the problems in one go.
|
After correcting these final validation problems and submitting again,
your order will be placed, and you'll see the final "Thank You" page, with a
reference to your order reference number. Clicking on the hyperlinked order
reference number takes you to an order summary page which is implemented using
the XML/XSLT-based
Oracle
XSQL Pages [19] publishing framework instead of JSP Pages, to illustrate
that multiple view-rendering technologies are possible.
Register a New User and Editing an
Existing User's Profile
If you are not currently logged-in as a
registered user of the web store, clicking the
button brings you to the "Sign In" page
as shown in Figure 6. From there, you can register as a new
user by clicking on the Register as a New User link. This
brings you to a form to complete with the necessary registration details.
This user registration page is another place in our application
where it's easy to observe how business rules get enforced by the ADF
framework. For example, if while filling out the form you try to:
- Enter a user name that has already been chosen by
another user
- Forget to provide a
password
- Enter an email address that is not
properly formed
then when you submit the
form, you'll see the full set of errors related to your registration as shown
in Figure 9  Figure 9: Validation
for New User Accounts In Action
| NOTE: |
Under
the covers, the business object that represents a user account is declaratively
enforcing mandatory attributes, reusing a custom business rule to validate the
country and state combination, using a built-in validation rule to enforce
uniqueness of the primary key attribute, and validating the correct formatting
of email addresses using a custom Email datatype. All of the
custom error messages are localized to the current browser user's locale (i.e.
language + territory). None of this behavior requires developer-written code to
coordinate.
|
If you are already logged into the site as a
registered user, you will see the
icon in the toolbar. Clicking on it brings you the page where you can edit your
account details as shown in Figure 10. Of course, since we're
working with the same underlying business object representing user accounts
here in this "Update Account" form, the same validation will be enforced as
above.
 Figure 10: Editing Account DetailsTrying Out the Demo in Another
Language
The demo is built using the internationalization features
supported by Struts and ADF Business Components, and it ships with support for
three languages: English (the default), Italian, and German. The Struts and ADF
frameworks automatically sense the language you want to see based on your
browser settings. So, you can see what the demo looks like in Italian by simply
setting your browser language preferences appropriately.
In
Mozilla Firefox [20]
1.0, you select your preferred languages on the General
panel of the Tools | Options... menu by clicking the
(Languages) button as shown in
Figure 11. You can add "Italian [it]" and then press
(Move Up) to move it to the top of the list.
 Figure 11: Changing the Preferred Language in Mozilla
Firefox 0.9
In Internet
Explorer, you can do the same thing from the General tab
of the Tools | Internet
Options... dialog by clicking on the
(Languages...) button.
Since Apache Struts
caches the browser-user's preferred language at the servlet session level, you
will need to close your browser window, and open a new one before you'll see
the demo change into Italian. A quick way to relaunch your preferred browser
with the right URL for the demo is to find the Target URL in the JDeveloper 10g
log window as shown in Figure 12 and click on
it.
 Figure 12: Clicking on the Target URL in
Log to Relaunch Browser
This will
bring up the ADF Toy Store demo again, but this time in Italian. After adding
the same items to your shopping cart again, it will look like what you see in
Figure 13.
 Figure 13: Shopping Cart
With Preferred Browser Language Set to Italian
You can set your
browser's preferred language back to English using similar steps, and close and
relaunch the browser window to proceed in English again. At this point we've
seen the key functionality in the demo, so it's time to dive in to understand
how it has all been built.
Dissecting the Demo
In
this section we explain the demo in detail, highlighting the interesting
details of how:
- The demo is architected
into Model, View, and Controller layers
- The
Model layer uses ADF's business service, data
access, and business object
components
- The business services can be
tested using JUnit
- The Controller layer
uses Struts actions to coordinate application flow
- The View layer uses standard Struts and JSTL tag libraries to simplify
building the web UI
- The ADF features for
seamless Struts integration work
- The features
of Struts and ADF are used to deliver a multilingual
application
- The your can use ADF with other
view layer technologies like Oracle XSQL Pages
- The default framework behavior can be customized fit your
needs.
| NOTE: |
To follow along, we assume
you have followed the instructions in the Demo Installation and
Setup section and
have the ADFToyStore.jws workspace open in the JDeveloper
IDE, and your default browser open to the ADF Toy Store home page as shown in
Figure 3.
|
How the Application is Organized Into Packages and Projects
Like all applications built in Java, the ADF Toy Store demo is comprised
of a set of classes, organized hierarchically into packages.
Figure 14 illustrates the key packages in the demo. We have
used the package naming to make it clear how the application classes break down
into model, view, and controller layers, as well as to clarify which classes
are part of our framework customizations and regression testing suite.
 Figure 14: Java Package Hierarchy for ADF Toy Store
demo
When building applications that leverage existing frameworks, your
application-specific classes inherit default functionality from an appropriate
framework base class. They inherit core behavior from their superclass, and add
application-specific logic and metadata. Typically, the only code needed in
your classes is the code that is specific to your application's business
functionality. Figure 15 shows some representative
examples of classes in the ADF Toy Store demo that inherit their behavior from
a framework:
- The main business service
component
toystore.model.services.ToyStoreService extends
the ADF framework base class
oracle.jbo.server.ApplicationModuleImpl, adding custom
business service methods and an application-specific "data model" of named
collections of data transfer objects (also known as value
objects) exposed to the client.
- An
example query component
toystore.model.dataaccess.ProductsInCategory extends the ADF
framework base class oracle.jbo.server.ViewObjectImpl,
adding an application-specific SQL query for products in a particular category
and providing custom methods to encapsulate the setting of its bind
parameters.
- An example business object
toystore.model.businessobjects.Account extends the ADF
framework base class oracle.jbo.server.EntityImpl, adding
application-specific attributes for user accounts and specifying several
business rules that govern an account's validity.
- The data transfer object
toystore.model.dataaccess.common.ShoppingCartRow extends the
ADF framework base interface oracle.jbo.Row, adding typesafe
access to the application-specific attributes in the row of shopping cart
information.
- The action
toystore.controller.strutsactions.PlaceOrderAction extends
the Struts framework base class
org.apache.struts.action.Action, adding application-specific
controller logic needed before rendering the HTML form to collect shipping
information for the order being placed.
- The
test case
toystore.test.unittests.CreateAnOrderTest extends
the JUnit framework base class junit.framework.TestCase,
adding application-specific testing logic that exercises the
ToyStoreService business service by simulating the creation
of an order after adding items to the shopping
cart.
 Figure 15: Example of Demo Classes that Extend Frameworks
JDeveloper 10g provides two constructs to organize our work: workspaces
and projects. Projects contain a set of files that get compiled (and perhaps
deployed) as a unit, and workspaces are a list of projects that go together to
comprise a complete application. Theoretically, we can build any application
with all of the files in a single project, but typically
we organize our work into a number of separate projects to divide up the work
into more logical groupings.
As shown in
Figure 16, the ADF Toy Store application is comprised
of a ADFToyStore workspace containing the following seven
projects:
-
ToyStoreModel.jpr
This project contains
the components in the toystore.model.* package tree,
including the main business service
toystore.model.services.ToyStoreService and all the business
object and data access components on which it relies to provide its application
functionality and model data to the client. It also contains the translated
resources (in English, Italian, and German) related to these
components.
-
ToyStoreViewController.jpr
This project
contains
- the JSP pages that comprise the
user interface of the web store, and the view-layer resource files in the
toystore.view package of the translatable text that appears
in all the pages.
- the Struts configuration
file
struts-config.xml and the source code for all of the
classes in the toystore.controller.* package tree. This
includes the Struts actions that coordinate the interaction between the
business service and the view-layer
pages.
-
ToyStoreViewControllerUIX.jpr
This is a
parallel view/controller project that illustrates the same application built
using a view layer comprised of Oracle ADF UIX pages instead of JSP pages. This
project contains
- the UIX pages that
comprise the user interface of the web store, and the view-layer resource files
in the
toystore.view package of the translatable text that
appears in all the pages.
- the Struts
configuration file
struts-config.xml and the source code for
all of the classes in the toystore.controller.* package
tree. This includes the Struts actions that coordinate the interaction between
the business service and the view-layer
pages.
-
FwkExtensions.jpr
This project contains
the classes in the toystore.fwk.* package tree that extend
the base ADF and Struts framework facilities to augment and/or customize the
default framework behavior. These customizations are not specific to the web
storefront and could be easily reused in another Struts/ADF
application.
-
Testing.jpr
This project contains the
classes in the toystore.test.* package tree, including a
JUnit regression test suite, test fixture, and unit tests for various aspects
of the ToyStoreService component.
-
DatabaseSetup.jpr
This project
contains the two SQL scripts used to setup the database schema for the demo, as
well as a JDeveloper database diagram of the Toy Store database
design.
-
Documentation.jpr
This project contains a
copy of this whitepaper in the readme.html
file.
 Figure 16: The ADFToyStore Workspace in the JDeveloper Application
NavigatorAdvantages of a Model/View/Controller
Architecture
First generation JSP applications freely mixed code
"scriptlets" into the page among the HTML presentation tags. The code for
parameter evaluation, data access, business rules enforcement, transaction
management, error handling, and page flow was simply typed right into the same
JSP file that would also eventually format the data for
the end-user to see. Having everything in one file and being able to see
compilation errors by refreshing the browser lent an immediacy to development
that enticed many developers to follow this approach. However, this hybrid
approach more often than not produced pages that were impossible to read.
Attempts to alter the look and feel of the pages, unless performed by the
original developer, could lead to hours of staring at the file, hunting for the
unintended typographical error.
Code scriptlets in JSP pages began
to fall out of favor as JSP 1.1's tag libraries allowed many common tasks to be
performed using easier-to-read elements and attributes. However, the popularity
of tag libraries that performed SQL data access or EJB component interaction
directly from the JSP page was still an indication that developers were not
correctly separating the presentation layer from the application layer. In
these first generation JSP applications, the model, view, and controller layers
were hopelessly intertwined.
As these applications evolved,
attempts to respond quickly to new business needs requiring an updated look and
feel or modified web page flow were greatly complicated by this "heavy page"
approach. Developers bitten by the maintenance nightmares of the
first-generation approach immediately understood the benefits that the Model,
View, and Controller separation has to offer. In a nutshell, with an MVC
architecture:
- Application look and feel
can change without affecting core application logic
- Page flow and error handling are centralized and removed from individual
pages
- Simpler-looking web pages can be
understood and modified by less technical team
members
With its advantages now clear,
let's begin to look at how our Toy Store demo implements the Model, View, and
Controller layers of its architecture.
Implementing the Model Layer Using ADF
Business Components
The model layer is comprised of business
services, query components, business objects, and collections of data transfer
objects that the business service exposes to the controller and view layers. In
this section we'll highlight some examples of these model layer components from
the ADF Toy Store demo and briefly explain how they leverage the ADF framework
for their implementation.
Considering Model Layer Approaches: EJB-Centric or
Web-Tier-Centric?
Before exploring the ADF Toy Store model layer
implementation in detail, we should first stop to consider the important choice
of whether the model layer will be implemented using:
- EJB Technology deployed to the J2EE EJB Tier,
or
- JavaBeans Technology deployed to the J2EE
Web Tier.
As illustrated by the two
separate sample applications provided by Sun's "J2EE
Blueprints" demo team, the approach you choose for your model layer can have a
major impact on the application's underlying implementation. The
architecture
documentation [21] that accompanies the more recent Adventure Builder demo
explains:
The
Java
Pet Store [9] application illustrates how to write a Website application in
an EJB-centric manner. The
Adventure Builder [22] application
illustrates the other option: how to write a Website application in a
Web-centric manner. EJB is a key technology in the J2EE platform, but not all
J2EE applications need to use it.
The document goes
on to explain some of the motivations behind making the choice:
One important design consideration is mapping application
modules and functionality to the different tiers and technologies on the J2EE
platform. Some choices are obvious, such as having a web tier when a web
browser client is required. Other choices may depend on several factors. Issues
such as data access and transactional needs, security, portability and
modularity of design, lead to deciding how to optimally map the application
modules to the client, Web, EJB, and EIS (data storage) tiers. An important
question is whether to use an EJB tier. Based on the application's needs, one
might choose not to use enterprise beans and the EJB container and tier. The
expertise of the development team also affects this decision. For example, a
team with strong Web-tier and SQL skills may find it easier to write a Web-only
application especially when they are new to the EJB technology and are pressed
for time to learn it.
Using the ADF framework, you
build your J2EE application using a consistent development approach that is
independent of your choice of deployment tier for your model layer. You
develop, test, and debug the application using a model layer built from
high-performance, well-architected, XML-configured JavaBeans. At any time
during the development process, you can choose to deploy your model layer as
JavaBeans to the J2EE Web Tier, or as an EJB Session Bean to the EJB tier. Some
business requirements that might nudge you in the direction of an EJB tier
deployment include the need to:
- Coordinate
ADF-powered services with other Session Beans in the same
transaction
- Leverage method-level security on
your ADF-backed services.
Since the ADF
framework provides an implementation of the best-practices
Business Delegate [23] design
pattern, your model and view layers are isolated from these deployment details.
Even if you change your mind mid-project on your preferred model-layer
deployment architecture, none of your application code needs to change. In
fact, you can try out both deployment options and pick the one that delivers
best performance for your particular application scenario. In other words,
using the ADF framework, you don't have to decide up front on an EJB-Centric or
Web-Tier-Centric approach, and you can change your mind at any time, without
rearchitecting your system.
For the purposes of this demo, we have
selected to deploy the ADF Toy Store demo's model layer to the J2EE web tier to
keep the demo as easy to follow as possible for the widest audience of Java
developers. For the reasons we've just mentioned, redeploying the model layer
to the EJB Tier would be a painless step for those wanting to take an
EJB-centric approach.
Implementing Business Services with ADF Application Module
Components
While Oracle ADF supports using virtually any kind of
Java class as a business service, the ADF Business Components option we provide
gives you the highest level of built-in application-building functionality and
developer productivity.
Business services built using the ADF
business components are called application modules. These
service components are:
- Cleanly
architected with a client-side business service interface
and server-tier implementation
- Efficiently
implemented as JavaBeans, but deployable as EJB Session Beans as necessary,
with support for container-managed transactions
- Automatically configured at runtime from XML metadata and created through
framework-supplied factories
- Easily used by
clients through ADF's implementation of the Business
Delegate design pattern
- Cleverly
designed to expose "active" collections of updateable data transfer objects
that interact with your business objects without
code
All of these features can be
summarized by saying that ADF-powered service components make the J2EE
developer's life a lot simpler. The key ADF framework components that cooperate
to provide the business service implementation are:
- Application Modules to build transactional
business services
- View
Objects and View Links to build collections of
updateable data transfer objects based on SQL queries
- Entity Objects and
Associations to encapsulate business rules and persistence
details of domain business objects and express the relationships between
them
- Domains - to build
custom datatypes, where necessary
Our
toystore.model.services.ToyStoreService application module
is the heart of our application. It is a JavaBean component that implements the
business service interface shown in
Example 1.
Example 1: ToyStoreService Business
Interface
package toystore.model.services.common;
public interface ToyStoreService extends ApplicationModule {
boolean validSignon(String username, String password);
boolean adjustQuantityInCart(String[] itemid, long[] qty);
boolean isCartEmpty();
long currentQuantityInCart(String itemid);
Double getCartTotal();
boolean adjustQuantitiesInCartAsStringArrays(String[] itemid,String[] qtyStrings);
String finalizeOrder();
void createNewOrder(String currentUsername);
void prepareToShowCategory(String id);
void prepareToShowProduct(String id);
void prepareToShowProductDetails(String id);
void prepareToSearch(String searchFor);
void prepareToCreateNewAccount();
void prepareToShowReviewOrder(String id);
boolean prepareToEditAccountInfoFor(String username);
} |
As shown in Figure 17, the
ToyStoreService component is implemented as a set of files.
The Application Navigator presents the component as a single, logical icon,
while the Structure Window's Sources folder shows the
detailed implementation files comprising that component:
ToyStoreService.xml - Service definition
file
ToyStoreService.java -
Service interface
ToyStoreServiceImpl.java - Service
implementation
ToyStoreServiceClient.java - Service client
proxy
| NOTE: |
There are four
ways to navigate to the files that comprise your ADF business
components:
- You can click on the component
in the Application Navigator and select one of the Go to
Class... options at the bottom of the right-mouse menu. For an
application module, you will see Go to Application Module
Class..., for example.
- You can
double-click on the source file name in the Structure Window's
Sources folder.
- You can
select Navigate | Go to Java Class... from the menu,
or type its key equivalent
Ctrl+Minus, and start
typing in the name of the class to get quick file-name completion (regardless
of what package the class is in).
- You can
select Navigate | Go to Recent Files... from the
menu, or type its key equivalent
Ctrl+=, and select it
from a list of recent files you've
edited.
|
The client proxy class is
created when you've exposed custom methods to b |