Skip Headers

Oracle® Application Development Framework Developer's Guide 10g Release 3 (10.1.3) B25386-01 |
| Home | Solution Area | Contents | Index

Previous | Next |

# 1.2 Development Process with Oracle ADF and JavaServer Faces

In this section, describes a simple example to acquaint you with the typical development process of building an Oracle ADF application with JavaServer Faces. This information is intended as a high-level overview of the basic workflow of J2EE application building with Oracle ADF.

## 1.2.1 Overview of the Steps for Building an Application

Our example is based on a highly-simplified version of the Service Request tracking system (the SRDemo sample), the real-world sample application used throughout the remainder of this guide. In the Service Request tracking system, external users log requests for technical assistance with products they've purchased. Internal users try to assist the customers in the area in which they have expertise. This introduction focuses on the basics, and examines a small slice of the system's functionality related to users and their areas of technical expertise.

You'll examine the steps involved in building a simple JSF page like the one you see in Figure 1-5 that allows the end user to browse for users by name, scroll through the results, and for each user found, see their areas of technical expertise.

Figure 1-5 Simple Browse Users Page with Search and Master/Detail Data

### 1.2.1.1 Starting by Creating a New Application

The first step in building a new application is to assign it a name and to specify the directory where its source files will be saved. Selecting Application from the JDeveloper New Gallery launches the Create Application dialog shown in Figure 1-6. Here you give the application a name, set a working directory, and provide a package prefix for the classes you'll create in the application. Suppose that you enter a package prefix of `oracle.srdemo` so that, by default, all of the classes will be created in packages whose names will begin with `oracle.srdemo.*`. Since you will be building a web application using JSF, EJB, and TopLink, Figure 1-6 shows the corresponding application template selected from the list. This application template is set up to create separate projects named Model and ViewController with appropriate technologies selected to build the respective layers of the application.

Figure 1-6 Creating a New Application Using an Application Template

### 1.2.1.2 Building the Business Service in the Model Project

You will typically start by building your business service interface, which by default is done in the project named Model. Your Model project will comprise an EJB 3.0 session bean to function as the service facade, and Java classes that represent the business domain objects you need to work with. The model doesn't need to be functionally complete to proceed on to the subsequent steps of developing the UI, but defining the service interface forces you to think about the data the view layer will need and the information it may need to supply as parameters to your service methods to complete the job. Since you'll want to work with users and areas of expertise, the Java classes named `User` and `ExpertiseArea` are created. Each class will contain properties to reflect the data needed to represent users and areas of expertise.

Based on the requirements, suppose the business service needs to support finding users by name. For this purpose, you can use the EJB Session Bean wizard to create a stateless EJB 3.0 session bean using a container-managed transaction. Next you can add a method called `findUsersByName()` to its local interface that accepts the matching pattern as a parameter called `name`. To clearly communicate the type of the result and obtain the best compile-time type checking possible, it is best practice to declare the return type of the method to be `List<User>`, a strongly typed list of User beans. Finally, you can write the method in the `SRServiceBean` class that implements the service interface. Figure 1-7 shows what the service and its classes look like in the Java class diagram in JDeveloper. You can see that the class also contains the useful `findAllUsers()` method to return all users if needed.

Figure 1-7 SRService Session Bean Facade and Supporting Domain Classes

Because of the clean separation that ADF Model affords between the service and the user interface, the remaining steps to build the page depend only on the service interface, not its implementation. You can begin with a service that returns static test data, but eventually you will want to map the `User` and `ExpertiseArea` classes to appropriate tables in your database. This is where Oracle TopLink excels, and JDeveloper's integrated support for configuring your TopLink session and mappings makes quick work of the task. If you already have database tables with similar structure to your classes, Oracle TopLink can "automap" the classes to the tables for you, and then you can adjust the results as needed. If the database tables do not exist yet, you can use JDeveloper's database diagrammer to design them before performing the mapping operation. To implement the `findUsersByName()` method, you will create a named query as part of the `User` mapping descriptor and provide the criteria required to retrieve users matching a name supplied as a parameter. At runtime, the Oracle TopLink runtime handles retrieving the results of the parameterized query from the database based on XML-driven object/relational mapping information.

### 1.2.1.3 Creating a Data Control for Your Service to Enable Data Binding

With the business service in place, you can begin to think about building the user interface. The first step in enabling drag-and-drop data binding for the business service is to create a data control for it. Creating the data control publishes the service interface to the rest of the Oracle ADF Model design time using JSR-227 service and structure descriptions. To create a data control, you just drag the `SRServiceBean` class onto JDeveloper's Data Control Palette. Figure 1-8 shows the Data Control Palette following this operation. You can see it reflects all of the service methods, any parameters they expect, and the method return types. For the `findUsersByName()` method, you can see that it expects a `name` parameter and that its return type contains beans of type `User`. The nested `email`, `lastName`, and `expertiseAreas` properties of the user are also displayed. Since `expertiseAreas` is a collection-typed property (of type `List<ExpertiseArea>`), you also see its nested properties. The Operations folder, shown collapsed in the figure, contains the built-in operations that the ADF Model layer supports on collections like Previous, Next, First, Last, and so on.

Figure 1-8 Data Control Palette Displays Services Declarative Data Binding

As you build your application, when you add additional methods on your service interface or change existing ones, simply drag and drop the `SRServiceBean` class again on to the Data Control Palette and the palette—as well as its underlying data binding metadata—will be refreshed to reflect your latest changes. The data control configuration information resides in an XML file named `DataControls.dcx` that JDeveloper adds to your `Model` project when you create the first data control. If you create multiple data controls, the information about the kind of data control they are (for example EJB, JavaBean, XML, Webservice, and so on.) and how to construct them at runtime lives in this file. In addition, JDeveloper creates an XML structure definition file for each data type involved in the service interface in a file whose name matches the name of that data type. For an EJB service interface, this means one structure definition file for the service class itself, and one for each JavaBean that appears as a method return value or method argument in the service interface.

These structure definition files drive the Data Control Palette display and come into play when you leverage the declarative, model-layer features like validators, prompts, tooltips, format masks, and declarative security. Since you defined these features at the model layer in these structure definition files, all your pages that present information related to these types display and validate the information in a consistent way. Figure 1-9 shows all of these files in the `Model` project in the Application Navigator after the data control for `SRServiceBean` has been created.

Figure 1-9 Service Classes and Data Control Metadata Files in Model Project

### 1.2.1.4 Dragging and Dropping Data to Create a New JSF Page

With the data control created, you can begin doing drag-and-drop data binding to create your page. Since you'll be using ADF Faces components in your page, you first ensure that the project's tag libraries are configured to use them. Double-clicking the ViewController project in the Application Navigator brings up the Project Properties dialog where you can see what libraries are configured on the JSP Tag Libraries page. If the ADF Faces Components and ADF Faces HTML libraries are missing, you can add them from here.

Figure 1-10 Configuring ViewController Project Tag Libraries to Use ADF Faces

Next, you use the Create JSF JSP wizard to create a page called `browseusers.jspx`. You may be more familiar working with JSP pages that have a `*.jsp` extension, but using a standard XML-based JSP "Document" instead is a best practice for JSF development since it:

- Simplifies treating your page as a well-formed tree of UI component tags

- Discourages you from mixing Java code and component tags

- Allows you to easily parse the page to create documentation or audit reports

When the Create JSF JSP wizard completes, JDeveloper opens the new page in the visual editor. From there, creating the databound page shown in Figure 1-11 is a completely drag-and-drop experience. As you drop elements from the Data Control Palette onto the page, a popup menu appears to show the sensible options for UI elements you can create for that element.

Figure 1-11 Browse Users JSF Page in the Visual Designer

The basic steps to create this page are:

1. Drop a panelHeader component from the ADF Faces Core page of the Component Palette onto the page and set its text attribute in the Property Inspector to "Browse Users and Expertise Areas".

2. Drop the findUsersByName() method from the Data Control Palette to create an ADF parameter form. This operation creates a `panelForm` component containing the label, field, and button to collect the value of the `name` parameter for passing to the method when the button is clicked.

3. Drop the User return value of the findUsersByName() node from the Data Control Palette to create an ADF read-only form. This operation creates a `panelForm` component containing the label and fields for the properties of the User bean.

4. Expand the Operations folder child of the User return value in the Data Control Palette and drop the built-in Previous operation to the page as a command button. Repeat to drop a Next button to the right of it.

5. Drop the expertiseAreas property nested inside the User return value in the Data Control Palette as an ADF read-only table. Select Enable Sorting in the Edit Table Columns dialog that appears to enable sorting the data by clicking on the column headers.

At any time you can run or debug your page to try out the user interface that you've built.

### 1.2.1.5 Examining the Binding Metadata Files Involved

The first time you drop a databound component from the Data Control Palette on a page, JDeveloper will create the page definition file for it. Figure 1-12 shows the contents of the `browseusersPageDef.xml` file in the Structure window. You can see that an action binding named `findUsersByName` will be created to invoke the service method of the same name. Iterator bindings named `findUsersByNameIter` and `expertiseAreasIterator` will be created to handle the collection of `User` beans returned from the service method and to handle the nested collection of `ExpertiseArea` beans. Action bindings named `Next` and `Previous` will be created to support the buttons that were dropped. And finally, attribute bindings of appropriate names will be created to support the read-only `outputText` fields and the table.

Figure 1-12 Page Definition XML File for browseusers.jsp

The very first time you perform Oracle ADF Model data binding in a project, JDeveloper creates one additional XML file called `DataBindings.cpx` that stores information about the mapping between page names and page definition names and lists the data controls that are in use in the project. Figure 1-13 shows what the `DataBindings.cpx` file looks like in the Structure window. At runtime, this file is used to create the overall Oracle ADF Model binding context. In addition, page map and page definition information from this file are used to instantiate the binding containers for pages as they are needed by the pages the user visits in your application.

Figure 1-13 Structure of DataBindings.cpx

Note: For complete details on the structure and contents of the `DataControls.dcx`, `DataBindings.cpx`, and `PageDef.xml` metadata files, see Appendix A, "Reference ADF XML Files".

### 1.2.1.6 Understanding How Components Reference Bindings via EL

As you perform drag-and-drop data binding operations, JDeveloper creates the required ADF Model binding metadata in the page definition and creates the JSF components you've requested. Importantly it also ties the two together by configuring various properties on the components to have EL expression values that reference the bindings. Figure 1-14 summarizes how the components on the page reference the bindings from the page's binding container at runtime.

Figure 1-14 EL Expressions Related Page Components to Bindings

As a simple example, take the Previous button. When you drop this built-in operation as a button, an action binding named `Previous` is created in the page definition file, and two properties of the `commandButton` component are set:

- `actionListener="#{bindings.Previous.execute}"`

- `disabled="#{!bindings.Previous.enabled}"`

These two EL expressions "wire" the button to invoke the built-in `Previous` operation and to automatically disable the button when the `Previous` operation does not make sense, such as when the user has navigated to the first row in the collection.

Studying another example in the page, like the read-only `outputText` field that displays the user's email, you would see that JDeveloper sets up the following properties on the component to refer to its binding:

- `value="#{bindings.email.inputValue}"`

- `label="#{bindings.email.label}"`

The combination of these two binding attribute settings tells the component to pull its value from the `email` binding, and to use the `email` binding's `label` property as a display label. Suppose you had configured custom prompts for the `User` and `ExpertiseArea` beans in the `Model` project, the bindings can then expose this information at runtime allowing the prompts to be referenced in a generic way by components on the page.

The drag-and-drop data binding steps above did not account for how the current record display (for example "N of M" ) appeared on the page. Since information about the current range of visible rows, the starting row in the range, and the total number of rows in the collection are useful properties available for reference on the iterator binding, to create this display, just drop three `outputText` components from the Component Palette and set each's `value` attribute to an appropriate expression. The first one needs to show the current row number in the range of results from the `findUsersByName` method, so it is necessary to set its `value` attribute to an EL expression that references the (zero-based!) `rangeStart` property on the `findUsersByNameIter` binding.

    #{bindings.findUsersByNameIter.rangeStart + 1}

The second `outputText` component just needs to show the word "of", so setting its `value` property to the constant string "`of`" will suffice. The third `outputText` component needs to show the total number of rows in the collection. Here, just a reference to an attribute on the iterator binding called `estimatedRowCount` is needed.

### 1.2.1.7 Configuring Binding Properties If Needed

Any time you want to see or set properties on bindings in the page definition, you can select Go to Page Definition in the context menu on the page. For example, you would do this to change the number of rows displayed per page for each iterator binding by setting its `RangeSize` property. In the example shown in Figure 1-14, after visiting the page definition, the Property Inspector was used to set the `RangeSize` of the `findUsersByNameIter` iterator binding to `1` and the same property of the `expertiseAreasIterator` to `2`. Setting the `RangeSize` property for each iterator causes one user and two expertise areas to display at a time on the page.

### 1.2.1.8 Understanding How Bindings Are Created at Runtime

The final piece of the puzzle to complete your basic understanding of Oracle ADF Model involves knowing how your data controls and declarative bindings are created at runtime based on the XML configuration files you've created. As part of configuring your project for working with Oracle ADF data binding, JDeveloper registers a servlet filter called `ADFBindingFilter` in the `web.xml` file of your `ViewController` project and maps this filter by default to URLs matching the pattern `*.jsp` and `*.jspx`.

This `ADFBindingFilter` servlet filter is responsible for finding your `DataBindings.cpx` file, based on the information in the `web.xml` file and creating the ADF binding context. The binding context is a Map that contains all binding containers, data controls, and the mapping of page names to page definition files. You can reference it at any time in your application using the EL expression `#{data}`. It's also the place where the centralized error handler is registered, and APIs are provided to set a custom error handler if needed (together with numerous other useful APIs).

When the page request is received the application invokes both the JSF lifecycle and the ADF lifecycle. Specifically, during execution of the ADF lifecycle execution, another object, the `ADFPhaseListener`, lazily instantiates the bindings in a binding container and data controls the first time they are needed to service a page request. The `ADFPhaseListener` references the information in the page map on the binding context to know which binding container to use for which page; it also references information in the `DataControls.dcx` file to know what data control factory to use. On each request, it ensures that the binding container of the current page being requested is available for reference via EL using the expression `#{bindings}`. Figure 1-15 summarizes the relationships between these metadata files.

Figure 1-15 How ADF Binding Metadata Is Used at Runtime

Once the binding container is set up for a given page, the `ADFPhaseListener` integrates the JSF page handling lifecycle with the bindings. It coordinates the per-page execution of the iterators and service methods based on information in the appropriate page definition file. The iterators and method invocation bindings are known as "executable" bindings for this reason.

## 1.2.2 Making the Display More Data-Driven

After you have a basic page working, you will likely notice some aspects that you'd like to make more sophisticated. For example, you can use the properties of ADF bindings to hide or show groups of components or to toggle between alternative sets of components.

### 1.2.2.1 Hiding and Showing Groups of Components Based on Binding Properties

If the application user enters a last name in the `browseusers.jspx` page that matches a single user, it doesn't look very nice to show disabled Next and Previous navigation buttons and a "1 of 1" record counter. Instead, you might want a result like what you see in Figure 1-16, where these components disappear when only a single row is returned.

Figure 1-16 Hiding Panel with Navigation Buttons When Not Relevant

Luckily, this is easy to accomplish. You start by organizing the navigation buttons and the record counter display into a containing panel component like `panelHorizontal`. After creating the panel to contain them, you can drag and drop in the visual editor, or drag and drop in the Structure window to place the existing controls inside another container. Then, to hide or show all the components in the panel, you just need to set the value of the panel's `rendered` attribute to a data-driven EL expression.

Recall that the number of rows in an iterator binding's collection can be obtained using its `estimatedRowCount` property. Figure 1-17 shows the EL picker dialog that appears when you select the `panelHorizontal` component, click in the Property Inspector on its `rendered` attribute, and click the ... button. If you expand the bindings for the current page you will see the `findUsersByNameIter` iterator binding. You can then expand it further to see the most common properties that developers reference in EL. By picking `estimatedRowCount` and clicking the > button, you can then change the expression to a boolean expression by introducing a comparison operator to compare the row count to see if it is greater than one. When you set such an expression, the panel will be rendered at runtime only when there are two or more rows in the result.

Figure 1-17 Setting a Panel's Rendered Attribute Based on Binding Properties

### 1.2.2.2 Toggling Between Alternative Sets of Components Based on Binding Properties

Consider another situation in the sample page. When no rows are returned, by default the read-only form would display its prompts next to empty space where the data values would normally be, and the table of experience areas would display the column headings and a blank row containing the words "No rows yet". To add a little more polish to the application, you might decide to display something different when no rows are returned in the iterator binding's result collection. For example, you might simply display a "No matches. Try again" message as shown in Figure 1-18.

Figure 1-18 Alternative Display If Search Produces Empty Collection

JSF provides a basic feature called a "facet" that allows a UI component to contain one or more named, logical groups of other components that become rendered in a specific way at runtime. ADF Faces supplies a handy `switcher` component that can evaluate an EL expression in its `FacetName` attribute to determine which of its facets becomes rendered at runtime. Using this component effectively lets you switch between any groups of components in a dynamic and declarative way. If you group the components that present the user information and experience area table into a panel, then you can use the `switcher` component to switch between showing that panel and a simple message depending on the number of rows returned.

Figure 1-19 shows the Structure window for the `browseusers.jsp` page reflecting the hierarchical containership of JSF components after the `switcher` component is introduced. First, you would set up two JSF facets and give them meaningful names like `found` and `notfound`. Then you can organize the existing components into the appropriate facet using drag and drop in the Structure window. In the `found` facet, you want a panel containing all of the components that show the user and experience area information. In the `notfound` facet, you want just an `outputText` component that displays the "No matches. Try again" message.

Figure 1-19 Structure Window View of browseusers.jsp

By setting the `facetName` attribute of `switcher` to the EL expression, the `found` facet will be used when the row count is greater than zero, and the `notfound` facet will be used when the row count equals zero:

`#{bindings.findUsersByNameIter.estimatedRowCount > 0 ?'found':'notfound'}`

The combination of Oracle ADF declarative bindings, ADF Faces components, and EL expressions demonstrates another situation that previously required tedious, repetitive coding which now can be handled with ease.

This concludes the introduction to building J2EE applications with Oracle ADF. The rest of this guide describes the details of building a real-world sample application using Oracle ADF, EJB, and JSF.