Oracle ADF Data Binding Primer and ADF/Struts Overview
Author: Steve Muench, JDeveloper/ADF Development TeamAbstract
This article explains the basics of the new Oracle Application Development Framework's data binding layer (based on JSR-227), gives an overview of the ADF runtime and design time data binding facilities, explains how ADF integrates with and supports easily building Struts-based web applications, and puts the concepts into practice with three simple example applications.
| NOTE: |
This whitepaper explains the new data binding concepts and facilities in the Oracle Application Development Framework (ADF) by explaining the interesting technical details of three simple, example applications that put the features into practice. If you plan to print the whitepaper and follow along offline, you should download the three example applications before unplugging from the network: ADFBindingInfo.zip [1], DataActionEventsExample.zip [2], and MethodBindingExample.zip [3]. This document goes into considerable technical depth about the main features of ADF data binding and Struts integration. If you are looking for a higher-level overview of the whole Oracle ADF framework, please see the Oracle Application Development Framework Overview [4] whitepaper (PDF format). |
Contents
IntroductionIntroduction
The new Oracle Application Development Framework [5] (ADF) in Oracle JDeveloper 10g evolves our road-tested BC4J [6] framework to a new level of flexibility and openness. By introducing a new "data control" abstraction for back-end business services and generalizing our existing data binding objects to support it, we've added a consistent and pluggable model layer to our J2EE application architecture.
Figure 1 illustrates where the ADF Data Control and ADF Bindings fit into the overall ADF Model, View, Controller, and Business Services architecture.

Oracle ADF provides out-of-the-box support for data controls based on Java classes, EJB Session Beans, Web Services and ADF Application Modules. Like other ADF components you may already be familiar with, both ADF Bindings and ADF Data Controls are configured using XML metadata so a small set of framework base classes can handle most of your application development needs without coding. When needs dictate, you can either customize the base framework classes or provide completely new data control and binding implementations.
As Figure 1 suggests, we've updated all of our existing view-layer technologies to support the ADF Bindings layer, so they now share both runtime and design time data binding functionality. This common data binding architecture, and our improved visual design time facilities that accompany it, are two cornerstones of JDeveloper 10g's "productivity with choice" value proposition.
In this article, we'll gain a high-level understanding of the Oracle ADF data binding concepts, see how we work with them at design time using Oracle JDeveloper 10g, and observe how they work in practice by studying a simple, working example of a Struts-based JSP application using Oracle ADF that complies with the best-practice Model, View, Controller design approach.
| NOTE: |
While not covered in-depth this article, it's also possible to use the ADF Binding facilities in JSP applications that do not use a formal controller layer like Struts. See the ADF Data Binding Q & A section below for more information on our support for this so-called "Model 1" JSP approach. |
Overview of ADF Data Binding Concepts
The key data binding concepts in Oracle ADF are the following:
Data Controls
A data control abstracts the implementation of a business service, allowing the binding layer to access the data from all services in a consistent way.
Iterator Bindings and Control Bindings
Bindings are lightweight objects that decouple back-end data and front-end UI display. An iterator binding provides a consistent way to work with a collection of data objects supplied by a data control. Control bindings provide a standard interface for UI components to interact with an iterator's data or to invoke "action" methods for preparing model data and handling events. Bindings also expose key metadata to simplify building dynamic, multi-lingual user interfaces.
Binding Containers
A binding container is a named group of of related iterator and control bindings that you use together for a particular page (or panel) of your application. A binding container is also known as a "UI Model" since it provides the appropriate subset of model data for a specific UI.
Binding Context
The binding context provides the data environment for your application. It contains all of the data controls and binding containers that your application can access.
Figure 2 shows what these concepts would look like in
simple Discussion Forum application. The ReviewThreads.jsp
page allows web users to review the open threads in a discussion forum, and
assign one or more threads to a given team to answer them. The page gets the
data about the discussion forums and the discussion threads they contain from a
service named ForumService, implemented using an ADF
Application Module. The data for the poplist on this page, containing the list
of valid team names for thread assignment, is pulled from a backend Web Service
named LookupCodes.
A data control
corresponding to each business service adapts it in a consistent way into the
ADF Binding model layer. The application's binding context contains two binding
containers, one named ReviewThreads used by the
ReviewThreads.jsp page, and another named
UnansweredPostings, shared by a uiXML page
(Page2.uix) and a JClient Swing panel
(Panel3.java). The ReviewThreads binding
container contains:
Forum and Threads data
collections are supplied by the ForumService, while the
Teams data collection is supplied by the LookupCodes
service.
Three control bindings to support the UI elements on the page:
<c:forEach> tag to loop over a selected range of multiple
attributes from the Teams data
source.
Note that the control value bindings reference the iterator bindings that provide their data. In the case of the list binding, it's related to two different iterators: one provides the values for the list, the other provides the target that will be updated if a new value is picked from the list.

Figure 3 illustrates how the concepts hang together at runtime. The application's binding context contains one or more data controls being used, as well as one or more binding containers that use them. Each binding container has one or more iterator bindings identifying the data collections used by a given page. Each iterator binding works with data from one particular data control. Binding containers also have one or more control bindings that support the UI controls in the page. Control bindings are related to an iterator when they are bound to data, or may be related straight to a data control if they are control action bindings, used to invoke custom data control methods.

Support for Existing and Emerging Standards
ADF Bindings have been designed with Java standards in mind, so they are easy to use with any client technology that can interact with JavaBean's and the Java Collections Framework. For example, popular tag libraries like the JSP Standard Tag Library [7] (JSTL) and those from the Jakarta Struts project now work seamlessly with Oracle ADF. You can use the standard Expression Language [8], common to both JSTL and JSP 2.0 [9], to easily work with data from your business services in your Web pages. For rich client applications with Swing UI's, we've refactored our existing JClient bindings to extend the base ADF Bindings functionality with additional bindings needed by more sophisticated Swing controls like trees, spinners, sliders, and others.
Oracle and other vendors [10] believe a common data binding facility should be a standard part of the Java platform, and as the specification lead on JSR 227 [11] Oracle is working with others as part of the Java Community Process [12] to make it happen. The ADF Bindings and ADF Data Control in JDeveloper 10g are an early implementation of the proposed JSR 227 data-binding facility and future ADF releases will evolve to support JSR 227's final API's and metadata.
ADF Binding Design Time Experience
JDeveloper 10g provides complete declarative design-time support for working with the JSR 227-style data binding that Oracle ADF offers. We'll focus our attention in this section specifically on how you work with the Oracle ADF Binding concepts we learned about above.
| NOTE: |
The screen shots in this section are based on the
|
Creating Data Controls
By default, any ADF Business Components application modules that you create are accessible as data controls. You need to explicitly create other kinds of data controls by selecting the Java Class, EJB Session Bean, or Web Service in the Application Navigator and either:
The
DataControls.dcx file appears automatically in any project
where you've created some data controls for business services that are
not implemented using ADF application modules. The file
stores a few pieces of basic metadata needed by the runtime framework about
your data controls. Figure 4 shows what you'll see if
you click on the DataControls.dcx file in the Application
Navigator. The Structure Pane shows the list of data controls you've defined.
If you're curious you can double-click on the file itself to see its XML
content in the source editor, but the file is read-only since its contents are
automatically managed by the JDeveloper 10g design time facilities.

In
the sample application that we'll be working with later in this article, I
created a JavaBean named test.model.beans.CommissionPlan and
another bean named test.model.services.CommissionService
with source code that looks like this:
package test.model.services;
import java.util.*;
import test.model.beans.CommissionPlan;
public class CommissionService {
private static final ArrayList plans = new ArrayList(4);
public CommissionService() {}
public Collection getAvailableCommissionPlans() {
return plans;
}
static {
plans.add(new CommissionPlan("High",2000));
plans.add(new CommissionPlan("Medium",1000));
plans.add(new CommissionPlan("Low",500));
}
}
When I selected Create Data
Control for CommissionService.java file in the
Application Navigator, the ADF design time created a companion
CommissionService.xml metadata file to record some extra
information required by the ADF runtime about this
service. Figure 5 shows what
selecting CommissionService.xml in the Application Navigator
looks like. The Structure Pane shows the properties and methods that this
service exposes, and the Property Inspector shows me the additional metadata
that ADF can record about the availableCommissionPlans
property.

Since introspection of the CommissionService only
tells us that the property is of type Collection, this
additional "Bean class" metadata property lets us record the specific kind of
bean that will be in the collection at runtime,
test.model.beans.CommissionPlan. I had to set this property
manually, using the Property Inspector. Once you tie the
CommissionPlan bean into the
CommissionService by setting this
BeanClass property, JDeveloper 10g creates the
CommissionPlan.xml metadata file as well to record metadata
about that bean as well.
| NOTE: |
Since ADF application modules already have their own XML metadata file, and already contain enough metadata to be exposed as a data control, no additional metadata files are needed for those. |
Figure 6 shows the kinds of data control implementations that are provided by default with Oracle ADF. Metadata recorded about your data controls provides the name of a factory class that will create instances of the appropriate data control implementation.

Designing UI's with the Data Control Palette
After you've created any necessary data controls, you can begin using them in your user interface projects. The new Data Control Palette shows you all of the available data controls in the current workspace, and presents their data and operations (methods) in a uniform way.
Data for iterator and control bindings can come from properties exposed by the
service, or from the return values of invoking service methods. Operations for
control action bindings can be built-in ones supplied by
the binding objects (like Create,
Delete, Next,
Previous, Save,
Commit, etc.) or be custom methods from your data
control's implementation. Figure 7 shows our
JavaBean-based data control named
CommissionServiceDataControl with the
availableCommissionPlans property we saw above. Its value is
a collection of (CommissionPlan) beans with
amount and name properties.

You can also
see a data control named EmpServiceDataControl for our
test.model.services.EmpService application module. Its
Employees property, a view object instance, is a set of rows
with attributes like Empno, Ename,
Hiredate, etc. Regardless of how the data is exposed, the
data binding experience is uniform for all kinds of back-end data
sources.
Notice the Drag and Drop As: poplist at the bottom of the Data Control Palette. When a web page or Swing panel is active, this area of the palette presents a list of commonly used UI elements that are appropriate for the combination of the selected data source and the active UI page or panel. Figure 8 shows the Drag and Drop As: choices available for a data collection with a JSP page active.

Of course, when working on a Swing panel or a uiXML page, a different
set of appropriate UI elements is presented. Also, the choices are different if
you select a single attribute like
Ename or amount, or an
operation in the palette, instead of a
collection.
Creating Binding Containers and Bindings
There are two ways to create binding containers and bindings: implicit and explicit.
Creating ADF Bindings the Implicit Way
When you drag and drop data-bound UI elements from the Data Control Palette to either the Visual Editor, Structure Pane, or the Code Editor, JDeveloper 10g will implicitly create bindings and a binding container to hold them if necessary. That is, it will:
| NOTE: |
The binding
container definition file is an XML file named
|
Figure 9 shows how you can use
the UI Model tab of the Structure Pane to view the
bindings in current page's binding container. With the
showEmployees.jsp page active in the visual editor, the
UI Model tab of the Structure pane shows the associated
showEmployeesUIModel binding container and the various
bindings it contains.
An obvious question is, "What's the difference between the Data Control Palette and the UI Model tab of the Structure Pane?" It's easy. The Data Control Palette shows all data controls in the workspace and represents all data that is available for binding. The UI Model tab shows the contents of the current page's binding container, representing the subset of data that the current page cares about displaying or modifying.

Bindings are described by metadata that lives in the binding container
XML file, however you never need to edit that XML file yourself. To set
properties on a binding, for example the iterator binding named
EmployeesIterator used by the
showEmployees.jsp page above, simply click on the binding in
the Structure Pane, and use the Property Inspector as shown in
Figure 10 to see or edit its settings.
| NOTE: |
Some more complex binding properties can only be set from the binding editor dialog. To bring up the binding editor dialog, click on the Edit... task link in the Property Inspector, or select Edit... from the context menu on the binding object in the Structure Pane. |

Notice the
value of the Model Reference property of the
EmployeesIteratoriterator binding in
the Property Inspector above. It is the standard "EL" (expression
language [8]) expression, relative to the binding context, that refers to
the data collection named Employees in the
EmpServiceDataControl data control.
If you
click on the control binding named Employees, a
Range binding used to display a table of rows, you will
notice in the Property Inspector that it has an IteratorName
property equal to EmployeesIterator. It is through these
property values that control bindings are related to iterator bindings and, in
turn, iterator bindings tied to the data in the data control that supplies
it.
Creating ADF Bindings the Explicit Way
In addition to the automatic drag and drop approach,
there is also a manual way to create binding containers and the bindings within
them. With a page or panel active in the editor, if you click on the
UI Model tab of the Structure Pane and see
"<no bindings>", then that tells you that the
current page has no associated binding container yet. If dragging and dropping
from the Data Control Palette is not your style, you can right-mouse on the
"<no bindings>" as shown in
Figure 11 and select the self-explanatory
Create UI Model menu choice to create the UI Model
for the page. This results in creating the
YourPageNameUIModel.xml file in
the directory indicated by your project's default package project-level
setting.

You can use the context menu in the UI Model tab of the Structure Pane to create new bindings in any binding container. Just select the root node in the tree that represents the binding container itself, and pick from the choices in the Create Binding context menu as shown in Figure 12.

The choices available in the Create Binding context menu allow you to create all of the principal kinds of binding objects shown in Figure 13. These framework binding classes are engaged at runtime based on the metadata recorded about your bindings in the binding container XML file. While not typically necessary, you can also provide custom binding implementations as well, or customized versions that extend the supplied binding classes.

When you create
a binding manually, the binding editor appears in order to capture the key
information needed to define the binding. If you don't like the default name of
your bindings, you can use the Property Inspector to change the value of the
id property of that binding. of the manually-created binding
to something more pleasing. If you need to delete a binding, you can just
select it and choose the Delete item from the
context menu. A warning will appear reminding you that you may need to revisit
any places in your page where you might be referencing the deleted
binding.
| NOTE: |
If you rename a binding, make sure to update places in your UI page or panel that might refer to the old name. If you rename an iterator binding, we try to cascade that name change to any control bindings in the binding container that might have referred to the old name. |
Seeing the Contents of Your Binding Context
As you use data controls and
create binding containers, JDeveloper 10g records the necessary metadata
describing them in the DataBindings.cpx file. Clicking on
the DataBindings.cpx file in the Application Navigator shows
the contents of your application's binding context in the Structure Pane.
Figure 14 shows that my ADFBindingIntro application has
two data controls, and uses one binding container (UI Model).

The
DataBindings.cpx file acts as the table of contents to the
data controls in use in this application. At runtime, the metadata definitions
for the data controls and binding containers are loaded lazily.
ADF Information in the Online Help
Before moving on to study a simple, working example, it's worth pointing out that the JDeveloper 10g online help provides additional details on ADF Data Controls and ADF Bindings. We also provide a link below to a number of helpful tutorials on using them with various clients and back-end business service implementations.
Select Help | Table of Contents from the main menu and the Help Navigator will appear as shown in Figure 15.

Start with the About Oracle ADF Data Controls topic shown in Figure 16.

After selecting the help topic and double-clicking on it, a new tab will appear in the editor area allowing you to read the help material.
If you want to keep the help system around without occupying screen real estate, you can click on the "Auto Hide" window icon as shown in Figure 17.

The Help Navigator window will auto-hide itself into the left margin of your screen as shown in Figure 18.

To refer at any time to the help, just hover your mouse over the Help "tile" in the margin for a second or two, and the Help Navigator will spring into view to allow you pick another topic. Once you've chosen a topic, the Help content window will auto-hide itself again. You can independently size auto-hidden windows so that you can make the auto-hidden Help contents window as wide as you need to. If after trying out the auto-hidden Help window you decide that you prefer to keep the window open, just click the Keep Open icon on the window title bar that looks like a little pushpin.
For more details on ADF Bindings, see the About the Oracle ADF Bindings topic shown in Figure 19.

For specific information about each ADF binding and the properties that it exposes to clients at runtime, see the About the Properties of the ADF Bindings topic shown in Figure 20.

| NOTE: |
When you have selected any binding in the UI Model tab of the Structure pane, you can press the F1 key to quickly jump to context-senstive online help for that binding type. This can be especially handy as a quick reference to the property names that are available from the binding using EL expressions. Similarly, if you right-mouse on a binding in the Structure Pane and select Goto JavaDoc..., you'll be brought to the JavaDoc for the underlying framework binding object supporting that particular binding. |
Finally, to see the available ADF-related tutorials, click on the Tutorials [13] link on the JDeveloper Welcome page. You can show the Welcome Page by selecting Welcome Page item in the Help main menu.
Understanding a Working Example Application
In this section we're going to study a simple Struts-based web application that makes use of an Oracle ADF binding container. You can download the ADFBindingIntro.zip [1] file containing the files needed to try the sample yourself.
| NOTE: |
You'll need to create a
connection named |
Overview of the Sample Application
The
ADFBindingIntro sample application consists of one main JSP
page named showEmployees.jsp which shows data from two
different data controls, one based on an ADF application module and the other
based on a simple Java Bean.
Figure 21 shows
what the main showEmployees.jsp page looks like in the new
JDeveloper 10g JSP Visual Editor. This page implements the view layer of our
application, and is cleanly separated from the model layer and the controller
layer as we'll see below.

We've used the new visual
Struts Page Flow diagram to build six different Struts actions, all of which
eventually forward to the same showEmployees.jsp page for
rendering the data. We have six different actions in order to illustrate some
different options you have for using ADF binding containers from your Struts
application. The approaches for using ADF with Struts fall into two main
categories:
DataAction, which
implements the basic page lifecycle for you.
For both of these approaches, we illustrate three different implementation variations to help you understand what is possible, and in doing so, help you identify which approach you might prefer for your ADF/Struts projects.
Figure 22 shows the page flow diagram with these six actions, one JSP page, and some three on-diagram notes.

The
index.jsp page shown in Figure 23 gives us
a starting page with links to exercise all six of our different actions. The
first three examples show different approaches for implementing the typical ADF
page handling lifecycle without using any ADF-supplied Struts action classes.
The second three examples show different approaches for accomplishing the same
functionality without having to write the page-lifecycle handling code
yourself. They take advantage of the ADF-supplied DataAction Struts action
which implements the page lifecycle for us. We'll study some interesting
details of these actions in sections that follow.

Basic Details of ADF/Struts Integration
The Oracle ADF runtime controller support for Struts in JDeveloper 10g is implemented a little differently than the JDeveloper9i BC4J/Struts support (described in detail in the BC4J Toy Store Demo [14] whitepaper), so I'll try to point out the salient differences.
In JDeveloper 9i, developers building BC4J/Struts
applications used the customized Struts request processor named
BC4JRequestProcessor to handle initializing the data binding
context and acquiring an instance of an appropriate application module. The use
of the custom request processor caused issues when developers tried to
integrate BC4J/Struts with Tiles or other technologies.
In JDeveloper 10g, our Struts integration comprises the following key elements:
ADFBindingFilter is a servlet filter in the
oracle.adf.model.servlet package that now handles
initializing the binding context as well as resource cleanup as part of
end-of-request handling.
DataAction in the
oracle.adf.controller.struts.actions package implements a
pluggable request handling lifecycle that is ADF
binding-container-aware.
DataActionMapping action mapping class in the
oracle.adf.controller.struts.actions package extends the
basic Struts action mapping to support a number of custom action properties
related to ADF data binding.
BindingContainerActionForm in the
oracle.adf.controller.struts.forms exposes the data in the
binding container as a Struts
DynaActionForm.
The six actions in our ADFBindingIntro sample application let us see how to use some or all of these elements as we'll see in the next section.
Examining Our ADF / Struts Example Actions
Next let's study the sample actions and how they work, highlighting which aspects of the ADF/Struts runtime integration they are making use of.
Setting Up the ADFBindingFilter
Before any of our Struts actions can access the
ADF binding context, we need to make sure the
ADFBindingFilter is properly configured in our
web.xml file. This is done for you
automatically by the JDeveloper 10g design time tools the
first time it's needed, but if you want to peek into the
web.xml file in the ViewController.jpr
project, you'll see the necessary entries:
:
<!-- ADF Binding Filter Class Setup -->
<filter>
<filter-name>ADFBindingFilter</filter-name>
<filter-class>oracle.adf.model.servlet.ADFBindingFilter</filter-class>
</filter>
<!--
| ADF Binding Filter Setup to engage the filter when
| the Struts "action" servlet is used.
+-->
<filter-mapping>
<filter-name>ADFBindingFilter</filter-name>
<servlet-name>action</servlet-name>
</filter-mapping>
<filter-mapping>
<filter-name>ADFBindingFilter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>ADFBindingFilter</filter-name>
<servlet-name>action</servlet-name>
</filter-mapping>
:
<!-- Servlet setup for the Struts action servlet -->
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
:
</servlet>
<!-- Servlet setup to map *.do URL's to the Struts action servlet -->
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
:
The ADFBindingFilter looks at the
value of the servlet context parameter named CpxFileName to
know which CPX file will be used to define this application's binding context.
In our sample application, you can see the following in the
web.xml file:
<context-param>
<param-name>CpxFileName</param-name>
<param-value>DataBindings</param-value>
</context-param>
This means that it will read the
DataBindings.cpx file to discover the contents of the
binding context.
Indicating the Binding Container for an Action
To
declaratively set the name of the ADF binding container to be used by a given
action, you can tailor the action to use the
DataActionMapping implementation class
(className), and add a nested
<set-property> tag to assign a value to the
modelReference property. The value of
modelReference should be the short name of one of the
binding containers listed in your DataBindings.cpx file.
Only the short name is needed. The fully-packaged-qualified name of the file
will be looked up from the binding context the first time the binding container
is used.
This is the snippet from our
struts-config.xml file that sets up our
/showEmpsActionCentric action, implemented by the
ShowEmpsActionCentricAction action class.
<action path="/showEmpsActionCentric"
className="oracle.adf.controller.struts.actions.DataActionMapping"
type="sample.controller.ShowEmpsActionCentricAction"
name="DataForm">
<set-property property="modelReference" value="showEmployeesUIModel"/>
<forward name="success" path="/showEmployees.jsp"/>
</action>Accessing the Binding Container
We can use code like the following to
access the binding container for an action based on the declarative
modelReference property setting in the Struts action
mapping:
/**
* Setup the binding container for use. Name of the binding container
* to use is gotten from the modelReference property on the Struts
* action mapping (through the extended DataActionMapping in the
* oracle.adf.controller.struts.actions package).
*/
private void initializeBindingContainer(ActionMapping mapping,
HttpServletRequest request) {
if (mapping instanceof DataActionMapping) {
DataActionMapping daMapping = (DataActionMapping)mapping;
String bindingContainerName = daMapping.getModelReference();
DCBindingContainer bc = getBindingContainer(request);
if(bc == null) {
BindingContext ctx = BindingContext.getContext(request);
bc = DCUtil.findBindingContainer(ctx, bindingContainerName);
if( bc != null) {
/*
* Put a reference to the binding container under the
* request-scoped attribute named "bindings" so JSP pages
* can easily refer to bindings in the binding container
* using EL expressions like ${bindings.Empno}
*/
request.setAttribute(BINDINGS, bc);
}
}
}
}
The code references the declarative
modelReference property from the action and uses the
getBindingContainer() helper method to see if the binding
container has already been setup during this request. If not, it calls
DCUtil.findBindingContainer() and then sets a
"bindings" attribute in the request scope so the view layer
page can access the binding container with EL expressions like
${bindings.BindingName}.
Accessing a Data Control
Once we have the binding container, we can find any bindings it contains. The data controls in use by the binding container are accessible via the iterator bindings that point to them. They can also be looked up explicitly by name from the binding context. The following sample code illustrates how we can lookup a data control by name. It also shows how to test for a particular data control implementation type -- like the ADF Business Components data control -- and how to return the service interface of its data provider:
protected ApplicationModule getApplicationModule(String dataControlName,
HttpServletRequest request) {
DCDataControl dc = getBindingContext(request).findDataControl(dataControlName);
/*
* Test to see if our data control is an instance of the ADF Business Components
* Data Control before trying to cast the data provider to a specific
* service interface
*/
if (dc instanceof DCJboDataControl) {
return (ApplicationModule) dc.getDataProvider();
}
return null;
}
The helper method used above to get hold of the binding context, looks like this:
protected BindingContext getBindingContext(HttpServletRequest request) {
return HttpBindingContext.getContext(request);
}Setting Up the Basic ADF Action Lifecycle
If we are not leveraging the built-in features of the ADF DataAction to handle the page lifecycle for use, we need to write code ourselves to do that. The basic steps in the lifecycle of handing the HTTP request involve:
ActionForwardSince all of our
hand-written actions will need to follow this approach, I've written a
BasicADFAction class in the sample that overrides the
default Struts action execute method to define this basic
lifecycle:
public final ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
return handleLifecycle(mapping, form, request, response);
}
I've made the execute() method
final to force subclasses to override specific lifecycle
methods in order to accomplish action-specific needs instead of trying to
override execute as might be their first inclination if they are already
familiar with Struts.
My handleLifecycle
method, called by the implementation of execute above, looks
like this:
protected ActionForward handleLifecycle(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
initializeBindingContainer(mapping, request);
ActionForward fwd = performActionLogic(mapping, form, request, response);
refreshBindingContainer(request);
return fwd;
}
My three custom Struts actions in the sample application:
ShowEmpActionCentricActionShowEmpsTypesafeActionShowEmpsActionBindingActionextend the BasicADFAction and override the
performActionLogic method to supply the custom controller
processing needed for that action.
Example of Writing Controller Code in the Action
The basic functionality that we are implementing in
this demonstration is to show an ordered list of employees. If the value of the
HTTP parameter named sort is missing or if it equals the
letter "a", then we want to perform an ascending sort. If
the value of the sort parameter is equal to the letter
"d", then we want to perform a descending sort.
The ShowEmpsActionCentricAction class illustrates how
to accomplish this functionality by writing all the model setup code directly
in the Struts action class. This is an approach that will be familiar to
developers using JDeveloper9i release 9.0.3 or 9.0.4:
public class ShowEmpsActionCentricAction extends BasicADFAction {
protected ActionForward performActionLogic(ActionMapping mapping,
ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
ApplicationModule am = getApplicationModule("EmpServiceDataControl", request);
ViewObject vo = am.findViewObject("Employees");
String sortDirection = request.getParameter("sort");
if ((sortDirection == null) || sortDirection.equals("a")) {
vo.setOrderByClause("sal asc");
}
else {
vo.setOrderByClause("sal desc");
}
vo.executeQuery();
return mapping.findForward("success");
}
}
This action code finds the application module (using an
appropriate helper method that it inherits from
BasicADFAction) and proceeds to set the ORDER BY clause of
the view object whose instance name is "Employees".
Using a Custom Method to Setup the Model Data
If your service is deployed on a remote server, it's
especially important that your client action code not make a lot of "chatty"
API invocations to the back-end business service across the wire. This is a
good reason why ADF application modules support exporting custom service
methods to clients. All model setup can be performed in a single round-trip to
the server. ShowEmpsTypesafeAction is a variant of the
ShowEmpsActionCentricAction that invokes the custom
prepareModelForShowEmployeesPage method on the application
module's custom service interface.
public class ShowEmpsTypesafeAction extends BasicADFAction {
protected ActionForward performActionLogic(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
/*
* "EmpService" is the custom business service interface created by
* the ADF Business Components wizard when you mark a custom method
* like "prepareModelForShowEmployeesPage" as exported to the client.
*/
EmpService svc = (EmpService)getApplicationModule("EmpServiceDataControl",request);
svc.prepareModelForShowEmployeesPage(request.getParameter("sort"));
return mapping.findForward("success");
}
}Using Action Bindings to Decouple Controller and Service
One of the ADF control bindings that we talked about in the first section of this paper was the "action binding". This binding object acts as an insulation layer between the client layer and the service methods on the data control. As an alternative to calling data control service methods directly in your code, you can use action bindings to further decouple the client layer from the business service. The action binding captures the metadata needed at runtime to invoke the service method, and can be used to invoke the underlying method -- passing any parameters as needed -- and retrieve its result (if any).
The code
for the ShowEmpsActionBindingAction variant that uses an
action binding to invoke the service method looks like this:
public class ShowEmpsActionBindingAction extends BasicADFAction {
protected ActionForward performActionLogic(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
invokeActionBinding("prepareModelForShowEmployeesPage",
request.getParameter("sort"), request);
return mapping.findForward("success");
}
}
The BasicADFAction base class
contains the helper method invokeActionBinding that
illustrates how you can provide an ArrayList of method
parameters to be passed to the service method being invoked. In this case, our
service method is void so we're not expecting a return
value, but if the method we're invoking returns something, we can retrieve the
return value by invoking the getResult() method on the
action binding object.
Using the DataAction for Full Lifecycle Support
The fourth Struts action
in the sample named "/showEmployeesTypesafe" is implemented
using the generic ADF-supplied DataAction class instead of a
custom-coded page lifecycle handling approach. The
DataAction is a Struts action that implements a much more
complete request-handling lifecycle than the trivial one we setup in our
BasicADFAction above. Keep in mind that what we did above
was for the simple read-only scenario in the demo. The
DataAction handles all of the typical situations you will
need while building Struts-based business applications.
Using an
approach structurally similar to the BasicADFAction, the
DataAction base class (in the
oracle.adf.controller.struts.actions package) overides the
base Struts action's execute() method and invokes a
handleLifecycle method that a number of protected lifecycle
methods to orchestrate the common steps that every request should follow.
The DataAction lifecycle handles:
ActionForward to decide where the flow of
control should go next, on to a page for rendering or on to another action.
In the demo we're using a
CustomizedDataAction class that extends the base ADF
DataAction to add a helper method named
invokeActionBinding() like we used in our hand-coded
BasicADFAction.
The
showEmployeesActionBindingAction class extends
CustomizedDataAction and overrides one of the lifecycle
methods that it inherits from DataAction named
prepareModel like this:
public class ShowEmployeesActionBindingAction extends CustomizedDataAction {
protected void prepareModel(DataActionContext ctx) throws Exception {
invokeActionBinding("prepareModelForShowEmployeesPage",
ctx.getHttpServletRequest().getParameter("sort"), ctx);
super.prepareModel(ctx);
}
}
Notice that rather than passing many parameters to each
method in the lifecycle, the ADF DataAction is designed to
pass the single DataActionContext object. This single
object, whose lifetime is only the current HTTP request being processed,
contains setter and getter methods to access any of the things your data action
subclasses might need. In the code above, we've called the
getHttpServletRequest() method to access the HTTP request
object to retrieve a parameter value for the sort parameter. Other handy
methods on the DataActionContext object like
getBindingContext() and
getBindingContainer(). Other methods on the
DataActionContext allow you to set the
ActionForward that will be used for determining where the
page flow will go next, as well as aspects related to Struts error reporting
and other functionality.
The key difference between the hand-coded examples and the DataAction is that with the DataAction, we don't have to write the page lifecycle handling code ourselves. Oracle has provided a rich, base implementation as a standard Struts action for you to extend and override where necessary with just application-specific code rather than request-handling "plumbing" code.
Using "Data Pages" to Simplify Your Page Flow Diagrams
It's often the case that a Struts action will be used both to:
This web design pattern, sometimes
called the "postback pattern", centralizes both the page initialization logic
and page event handling into the same action class. Oracle ADF provides the
DataForwardAction (which extends
DataAction) that caters to this web design pattern and
allows you to simplify your page flow diagrams by using it.
The
DataForwardAction combines the lifecycle features of the ADF
DataAction with the implicit page forwarding behavior of the
basic Struts ForwardAction [15]. Since
by design the DataForwardAction always forwards to the same
page for rendering, which in turn contains forms or hyperlinks that
post back to that same action to handle any of the page's
events, JDeveloper shows the pair of action and page as a single "Data Page"
icon in the diagram.
As shown in Figure 24 you can
hover your mouse of the icon for a data page and see both the name of the
action class and the associated page. We can see that this
/showEmployeesTypesafe action also forwards to the same
"/showEmployees.jsp" page, although it does so implicitly
instead of via an explicit forward.

| NOTE: |
Similar to the
Struts |
The
ShowEmployeesTypesafeAction class shown below illustrates
that using the DataForwardAction, we can use the same
typesafe service interface approach shown earlier to invoke a method on the
data control's data provider service.
public class ShowEmployeesTypesafeAction extends DataForwardAction {
protected void prepareModel(DataActionContext ctx) throws Exception {
/*
* "EmpService" is the custom business service interface created by
* the ADF Business Components wizard when you mark a custom method
* like "prepareModelForShowEmployeesPage" as exported to the client.
*/
EmpService svc = (EmpService)ctx.getBindingContext()
.findDataControl("EmpServiceDataControl")
.getDataProvider();
svc.prepareModelForShowEmployeesPage(
ctx.getHttpServletRequest().getParameter("sort"));
super.prepareModel(ctx);
}Using DataAction Features to Go Totally Declarative
Our final example is the
/showEmployeesDeclarative action. This "data page"
accomplishes the same functionality as the ones we've seen before, but it does
so without any custom code whatsoever. The DataAction and
DataForwardAction (used by "data pages") support the ability
to declaratively invoke a service method from the data control.
We
saw in the /showEmpsActionBinding and
/showEmployeesActionBinding examples that ADF
action bindings can be used to encapsulate the interaction
with a data control's service methods. To support fully-declarative method
invocation, the DataAction integrates the optional feature
of:
Here's how I
setup the declarative method invocation being performed by the
/showEmployeesDeclarative data action. Using the Data
Control Palette, by dragging the
prepareModelForShowEmployeesPage operation for the the
EmpServiceDataControl data control and dropping it onto the
"/showEmployeesDeclarative" data action in the page flow
diagram, the JDeveloper 10g design time automatically set up the necessary
properties in the struts-config.xml file to allow that
DataAction to perform the invocation of the
prepareModelForShowEmployeesPage method at runtime.
In addition to the modelReference property we saw
above, you can see in the <action> entry below the additional
properties like methodName,
resultLocation, numParams, and
paramNames[0]. The value of numParams
indicates the our prepareModelForShowEmployeesPage method
accepts one argument, and the paramNames[0] property
supplies the EL expression to evaluate to provide the value of that property
when the method is invoked by the framework. The expression
${param.sort} is the standard EL syntax to refer to the HTTP
request parameter named sort.
<action path="/showEmployeesDeclarative"
className="oracle.adf.controller.struts.actions.DataActionMapping"
name="DataForm"
parameter="/showEmployees.jsp"
type="oracle.adf.controller.struts.actions.DataForwardAction">
<set-property property="modelReference"
value="showEmployeesUIModel"/>
<set-property property="methodName"
value="showEmployeesUIModel.prepareModelForShowEmployeesPage"/>
<set-property property="resultLocation"
value="${requestScope.methodResult}"/>
<set-property property="numParams"
value="1"/>
<set-property property="paramNames[0]"
value="${param.sort}"/>
</action>
The result is that without having to write any
controller code for /showEmployeesDeclarative, the data
control method is invoked to prepare the model, and the default "success"
forward is returned to forward control to the
showEmployees.jsp page for rendering.
To
understand the different methods in the DataAction
lifecycle, you can refer to the JavaDoc for the
handleLifecycle method in the DataAction
class, or have a look at its source code. To jump quickly to any ADF Binding or
ADF Struts controller source code or JavaDoc, just use the new
Navigate | Go to Java
Class main menu selection or press the accelerator key
Ctrl+Minus. You'll see
the dialog shown in Figure 25 where you can just start
typing the name of the class (without having to recall what package it lives
in!) into the Name field. Hitting Enter
opens the source code (or JavaDoc) for the desired class.

| NOTE: |
Source code for ADF Bindings, ADF Data Controls and ADF Struts controller support are provided with the release. For convenience, the Struts controller source code is also provided. |
Using EL Expressions to Refer to Data in Web Pages
The sample
showEmployees.jsp page uses tags in the "core"
JSTL [7]
tag library which support the use of a standard
expression
language [8] for referencing beans and collections. For example, to keep
the expressions shorter, at the top of the page you'll find:
<%--
| Capture Employees and CommissionPlans bindings
| into variables with shorter names
+--%>
<c:set var="e" value="${bindings.Employees}"/>
<c:set var="c" value="${bindings.availableCommissionPlans}"/>
This creates variables named "e" and "c" respectively
to hold the Employees range binding object, and the
availableCommissionPlans range binding object. The
expression ${bindings.Employees} refers to the member
property named Employees in the object named
bindings.
| NOTE: |
Click here [16] or here [17] for handy quick references to JSTL and its Expression Language. (PDF format) |
Recall that in our
BasicADFAction, after finding the binding container, we set
a request-scope attribute named bindings to have the value
of the binding container. The DataAction performs this same
task for us, as well, using the same attribute name
bindings. This allows our JSP pages to refer to the binding
container with the expression ${bindings} and by using dot
notation, to any binding in the binding container using
${bindings.BindingName}. By
assigning a shorter variable name "e" to the value of the
expression ${bindings.Employees} inside the page using
<c:set>, we can subsequently write an expression like
${e.labels.Ename} instead of the longer
${bindings.Employees.labels.Ename}.
This
simple example of refering to the labels property of the
range binding in our table headers shows just one of the helpful pieces of
information the binding object makes available to your page. If you click on
the index.html file in the
ViewController.jpr file and run it, then click on one of the
links in that home page to exercise your favorite action, you should see the
page shown in Figure 26.
Notice that the
column titles show up as "Id", "Employee Name", and "Salary", instead of the
raw attribute names Empno, Ename, and
Sal. This happens because we defined UI control hints for
the human-readable labels of the attributes on the Emp
entity object. The labels property on the binding gives the
client easy access to these locale-sensitive UI hints.
| NOTE: |
To see all of the properties available via EL expressions for any binding, just click on the binding in the UI Model tab of the Structure Pane and press F1 for help. |

Rendering the table
is accomplished by using the JSTL <c:forEach> tag. For
example, the rows of the employee table are rendered with this fragment of
tags:
<!--
| REMEMBER that "e" is a local variable assigned to ${bindings.Employees}
| range control binding at the top of this JSP page
+-->
<c:forEach var="x" items="${e.rangeSet}" varStatus="idx">
<tr class="r<c:out value='${idx.index % 2}'/>">
<td><c:out value="${x.Empno}"/></td>
<td><c:out value="${x.Ename}"/></td>
<td><c:out value="${x.Sal}"/></td>
</tr>
</c:forEach>
The rangeSet property of the
Employees range binding exposes the rows in the current
range of the view object as a collection. The var="x"
attribute of the <c:forEach> tag assigns a looping variable
named "x" and then the tags inside the loop refer to the
values of the attributes in each row bean by using EL dot notation. The
varStatus="idx" attribute of the
<c:forEach> tag assigns a looping status
variable named "idx". The JSTL specification tells us that
this object has a property named index that tells us which
row of the iteration we are on. Notice the line above that looks like:
<tr class="r<c:out value='${idx.index % 2}'/>">
Here we're using the JSTL <c:out> tag
as an embedded part of the <tr> tag's class
attribute value. Since the idx.index value, modulo 2, will
alternate between 1 and 0 for odd and
even row numbers, the result will be CSS class names that alternate between the
values "r1" and "r0". This makes it easy
to color odd and even rows differently in the demo using CSS classes defined in
the ./css/blaf.css stylesheet that is part of the
demo.
To experience the full extent of the application's
(admittedly meager!) functionality, click on the tiny arrow next to the
"Salary" header to toggle between ascending and descending order for the rows.
"Why do we only see five EMP rows?" you ask. Easy. Just
click on the EmployeesIterator iterator binding in the UI
Model Structure Pane tab for the showEmployees.jsp page, and
you'll see in the Property Inspector (as we saw above in
Figure 10) that the "Range Size" property is set to
5. With ADF Bindings, all of the mechanics of data binding
are cleanly factored out into binding metadata in your binding container. The
UI client pages and panels only need to refer to the bindings they want to work
with.
| NOTE: |
For web applications, the ADF framework automatically "prepares" the correct binding container for the current page request during the "prepareModel" phase of the lifecycle, and releases any state held by the bindings in that current binding container at the end of the request. This improves scalability by avoiding unnecessary session-level state. It is best practice that each page's binding container contain all the bindings that it needs to reference. In other words, instead of referencing a binding from another binding container using an expression like:
create a binding in the current page's binding container that refers to the same iterator(s) and attributes and use the expression:
This way each page is self-contained with respect to its bindings. |
Understanding ADF DataAction Event Handling
In order to
build more sophisticated and dynamic applications, the ADF DataAction provides
a simple-to-use event-handling mechanism that allows you to control what
happens when your end-user clicks on certain buttons or links in your pages.
This section explains the basics by walking through the small example
application that you can download from here:
DataActionEventsExample.zip [2].
| NOTE: |
To run the example, you will need to have first defined a database
connection in the JDeveloper 10g Connection Navigator with the name
" |
The DataAction Events Sample Application
Figure 27 shows
the page flow for the DataAction Events Example application. After extracting
the example zip file and opening the
DataActionEventsExample.jws workspace in JDeveloper 10g, you
can see the diagram in your own environment by clicking on the
ViewController project and selecting Open Struts
Page Flow Diagram... from the right-mouse context menu.

| NOTE: |
Notice that the Page Flow diagram shows Struts forwards as solid lines with the forward name next to the line (e.g. "winner", "success", "SaveAll", etc. in Figure 27), while the dotted lines represent normal web page links based on:
When using ADF DataPages (shown in the page flow diagram as "page-with-database-can" icons) , we consciously omit the dotted line from the page back to itself that represents the "postback pattern". In usability testing, most users commented that showing those postback form submissions just cluttered up the diagram. |
Running the ViewController project will bring up the
demo home page (index.jsp) that you see in
Figure 28.

| NOTE: |
JDeveloper
knows which page to run when you run the |
The
Struts DispatchAction Example
(DispatchExample), ADF DataPage Example
(DataPageExample) and Example2
(DataPageExample2), and ADF Declarative Example
(DataPageDeclarative) all implement the same, simple
functionality of allowing the user to increment, decrement, or update the value
of an integer. When the user performs an action that results in the integer's
value changing to the "magic number" 10, we shown them a page that says "You
Win!". We will study them to understand the different approaches available for
handling page events while using Oracle ADF and Struts.
The
Events, Actions, and Forwards Example
(UpdateEmp1 and UpdateEmp2) uses a simple
employee editing form, implemented across two different pages, to show off the
remaining interesting aspects about the ADF event-handling
mechanism.
What Are Events in a Web Application?
Java developers who work with JavaBeans or who
build user interfaces with
Swing [18] are
familiar with the notion that Java components can expose a set of well-defined
events. For example, a Swing JButton object has an event
named actionPerformed that will "fire" when the end-user
clicks on the button. To handle the events, developers write code in
event-handling methods that get invoked when a specific event occurs on a
specific component at runtime. For instance, they might write a method like the
following to respond to a click on the (Update) button in
a dialog:
/**
* Event handler for the actionPerformed event on JButton instance "updateButton".
*/
private void updateButton_actionPerformed(ActionEvent e) {
// Do something here when the [Update] button is pressed
}
Prior to beginning to experiment with JavaServer Faces 1.0 [19] which debuted in March 2004, web developers on the J2EE platform have not had any server-side, web-based analog to the Swing visual controls that support well-defined events. So nearly all J2EE web developers to date have invented their own approaches to identify what actions the user has performed in the browser so that their middle-tier code can react accordingly.
One common approach is to use a parameter named
event whose value indicates which event
should fire. For example, given the following two buttons and a hyperlink in an
HTML page:

web developers
might code these to each use the event parameter name in
their JSP page like this:
<%-- Excerpt of code in SomePage.jsp --%>
:
<form action="SomePage.jsp" method="post">
:
<input type="submit" name="event" value="Update"/>
<input type="submit" name="event" value="Increment"/>
<a href="SomePage.jsp?event=Decrement">Remove One</a>
</form>
Then, they would include code either directly in the JSP
page, or in a bean used by the page, to test for the presence of an
event parameter, and conditionally call event handling code
based on the value like this:
<%-- Excerpt of code in SomePage.jsp --%>
<%
String event = request.getParameter("event");
&nb