This chapter describes how to use the Data Controls panel and ADF Model data binding to create databound UI components on JSF pages of a Fusion web application. It describes how to use page templates and page fragments to build a page. It also describes how to use managed beans to store logic for the page.
This chapter includes the following sections:
Section 22.1, "Introduction to Developing a Web Application with ADF Faces"
Section 22.4, "Using a Managed Bean in a Fusion Web Application"
Most of what you need to know to get started with your web interface is covered in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework. However, using the ADF Model layer for data binding instead of JSF managed beans provides additional functionality, such as the ability to declaratively bind components to your business services. For more information on what ADF Model can provide, see Section 1.2.2, "ADF Model Layer." This chapter provides a high-level overview of the web interface development process as detailed in the Faces guide, and also provides information about the additional functionality available when you use ADF Model data binding.
Following the development process outlined in Chapter 1, "Introduction to Building Fusion Web Applications with Oracle ADF", developing a web application with ADF Faces and using ADF Model for data binding involves the following steps:
Creating ADF Faces templates for your pages (optional)
Creating the individual pages and page fragments for regions to be used within a page
Creating any needed managed beans
Additionally, the lifecycle of a Fusion web application is different from that of a standard JSF or ADF Faces application. For more information about how the lifecycle works, see Chapter 23, "Understanding the Fusion Page Lifecycle."
As you design the flow of your application, you can begin to think about the design of your pages. To ensure consistency throughout your application, you use ADF page templates. These page templates provide structure and consistency for other developers building web pages. Page templates typically contain static areas which cannot be changed when they are used, and dynamic areas, where developers can place content specific to the page they are building.
For example, the StoreFront module of the Fusion Order Demo application contains a page template that provides a top area for branding and navigation, a bottom area for copyright information, and a center area for the main content of the page. Page developers do not need to do anything to the branding and copyright information when they use the template. They need only to develop the main content area.
In addition to using ADF Faces components to build a page template, you can add attributes to the template definition. These attributes provide placeholders for specific information that the page developer needs to provide when using the page template. For example, the page template in the StoreFront module application contains an attribute for a welcome message. When page developers use this page template, they can add a different welcome message for each page.
You can also add facet references to the page template. These references act as placeholders for content on the page. Figure 22-1 shows a rendition of how the StoreFrontTemplate
template used in the StoreFront module application uses facet references.
In this page template, facet references are used inside four different panelSplitter
components. When the home page was created using this page template, the navigational links were placed in the Header facet and the accordion panels that hold the navigation trees and search panels were placed in the Start facet. The cart summary was placed in the End facet, and the main portion of the page was placed in the Center facet. The copyright information was placed in the Bottom facet.
When you choose to add databound components to a page template, an associated page definition file and the other metadata files that support ADF Model layer data binding are created. Each component is bound in the same fashion as for standard JSF pages, as described in Chapter 13, "Using ADF Model in a Fusion Web Application." You can also create model parameters for the page template. The values for these parameters can then be set at runtime by the calling page.
For example, if you wanted a list of products to appear on each page that uses the page template, you could drag and drop the ProductName
attribute of the Products
collection as a list. Or, if you wanted the pages to display the currently selected product ID, you could create a model parameter for the page template that would evaluate to that product's ID.
Note:
Page templates are primarily a project artifact. While they can be reused between projects and applications, they are not fully self-contained and will always have some dependencies to external resources, for example, any ADF data binding,Strings
from a message bundle, images, and managed beans.If a page template does not contain databound components, it can be referenced dynamically by the calling page using an EL expression. That is, the page template to be used can be determined at runtime. For instance, a page may use templateA or templateB based on user selection. When you add a page template to a page, an af:pageTemplate
tag is added to the page. The af:pageTemplate
tag includes a viewId
attribute that specifies the page template the page will use. You can set viewId
with an EL expression to a managed bean method that returns the page template Id
, as shown in Example 22-1.
Example 22-1 Page with Dynamic Page Template (not Databound Page Template Only)
<af:pageTemplate id="pt1" viewId="#{myBean.templateViewId}"
If the page template has databound components, setting the viewId
with an EL expression is not enough. Because databound components require access to the binding container, you must specify the page template as well as its associated binding container.
For databound page templates, you use the pageTemplateModel
to manage both the page template Id
and the associated binding container. In the JSF page, instead of using the viewId
attribute, you set the value
attribute to the pageTemplateModel
. You must also modify the page executable section of the calling page's page definition file and create a managed bean with methods to process the page template Id
s. For detailed instructions, see Section 22.2.3, "How to Add a Databound Page Template to a Page Dynamically."
Creating a page template for use in an application that uses ADF Business Components and ADF Model layer data binding is the same as creating a standard ADF Faces page template, as documented in the "Using Page Templates" section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework. Once you create the template, you can drag and drop items from the Data Controls panel. JDeveloper automatically adds the page definition file when you drag and drop items from this panel.
The Create JSF Page Template wizard also allows you to create model parameters for use by the template.
To add model parameters to a template:
Create a page template following the instructions in the "How to Create a Page Template" section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework. However, do not complete the dialog.
In the Create JSF Page Template dialog, select Create Associated ADFm Page Definition.
Note:
You only need to select this checkbox if you wish to add parameters. JDeveloper automatically adds the page definition file when you drag and drop items from the Data Controls panel.Click the Model Parameters tab.
Click the Add icon.
Enter the following for the parameter:
Id: Enter a name for the parameter.
Value: Enter a value or an EL expression that can resolve to a value. If needed, click the Invoke Expression Builder (...) button to open the Expression Builder. You can use this to build the expression. For more information about EL expressions and the EL expression builder, see Chapter 13, "Creating ADF Data Binding EL Expressions."
Option: Select the option that determines how the parameter value will be specified.
optional: The binding definition's value is used only if the parameter is not specifically set by the caller. This is the default.
final: The binding definition has the expression to access the value that should be used for this parameter.
mandatory: The parameter value has to be set by the caller.
Read Only: Select if the parameter's value is to be read-only and should not be overwritten
Create more parameters as needed. Use the order buttons to arrange the parameters into the order in which you want them to be evaluated.
You can now use the Data Controls panel to add databound UI components to the page, as you would for a standard JSF page, as described in the remaining chapters in this part of the book.
Note:
If your template contains any method actions bound to a method iterator, you cannot change the value of therefresh
attribute on the iterator to anything other than Default
. If set to anything other than Default
, the method will not execute.When you add ADF databound components to a template or create model parameters for a template, a page definition file is created for the template, and any model parameters are added to that file.
Note:
This section describes what happens for a statically assigned page template. For information about dynamic templates, see Section 22.2.3, "How to Add a Databound Page Template to a Page Dynamically."Example 22-2 shows what the page definition file for a template for which you created a productId
model parameter might look like.
Example 22-2 Model Parameters in a Page Definition for a Template
<parameters> <parameter id="productID" readonly="true" value="#{bindings.productId.inputValue}"/> </parameters> <executables/> <bindings/>
Parameter binding objects declare the parameters that the page evaluates at the beginning of a request. For more information about binding objects and the ADF lifecycle, see Chapter 13, "Using ADF Model in a Fusion Web Application." However, since a template itself is never executed, the page that uses the template (the calling page) must access the binding objects created for the template (including parameters or any other type of binding objects created by dragging and dropping objects from the Data Controls panel onto the template).
In order to access the template's binding objects, the page definition file for the calling page must instantiate the binding container represented by the template's page definition file. As a result, a reference to the template's page definition is inserted as an executable into the calling page's page definition file, as shown in Example 22-3.
Example 22-3 Reference to Template's Page Definition as an Executable
<executables> <page path="oracle.foddemo.storefront.pageDefs.templates_MyTemplatePageDef" id="pageTemplateBinding"/> </executables>
In this example, the calling page was built using the MyTemplate
template. Because the page definition file for the MyTemplate
template appears as an executable for the calling page, when the calling page's binding container is instantiated, it will in turn instantiate the MyTemplatePageDef
's binding container, thus allowing access to the parameter values or any other databound values.
Because there is an ID for this reference (in this case, pageTemplateBinding
), the calling page can have components that are able to access values from the template. When you create a JSF page from a template, instead of you having to repeat the code contained within the template, you can use the af:pageTemplate
tag on the calling page. This tag contains the path to the template JSF page.
Additionally, when the template contains any ADF data binding, the value of that tag is the ID set for the calling page's reference to the template's page definition, as shown in Example 22-4. This binding allows the component access to the binding values from the template.
You can dynamically add a page template without databound components by using an EL expression to select the page template. For more information on how to do this, see Section 22.2, "Using Page Templates."
You can also statically add a page template with databound components. For more information on how to do this, see Section 22.2.1, "How to Use ADF Data Binding in ADF Page Templates."
This section describes how to dynamically add a page template with databound components to a page.
You use the pageTemplateModel
to dynamically manage a page template and its binding container. You use an EL expression in the page definition file to set the page template Id
. You create managed bean methods to return the page template Id
.
To add a databound page template to a page dynamically:
Add the page template to the page as described in Section 22.2.1, "How to Use ADF Data Binding in ADF Page Templates."
In the JSF page source editor, remove the viewId
attribute and change the value
attribute to the pageTemplateModel
. You do not need to create a pageTemplateModel
explicitly. You can use the pageTemplateModel
from the corresponding page definition file's page executable binding. For example, for a page executable binding called pageTemplate1
, you would add the following line under the af:pageTemplate
tag:
value="#{bindings.pageTemplate1.templateModel}"/>
In the page definition file <executable>
section, make the following changes to the <page>
section:
Remove the path
attribute. It is no longer needed. The pageTemplateModel
manages databound components' access to the binding container.
Change the id
attribute to the page executable binding. In this example, it is pageTemplate1
.
Add a Refresh
attribute and set it to ifNeeded
.
Add a viewId
attribute and set it to an EL expression with a managed bean method that returns the current page template Id
.
For example, for a page executable binding of pageTemplate1
, the id
attribute would also be pageTemplate1
:
<executables> <page id="pageTemplate1" viewId="#{myBean.templateViewId}" Refresh="ifNeeded"/> ... </executables>
Create a pageFlowScope
managed bean with a method that returns the current page template Id
.
The managed bean code should be similar to that of Example 22-5. In this example, gettemplateViewId()
obtains the user's page template selection and returns the page template Id
. setMDTemplateViewId()
sets the page template to be MDPageTemplate
and setPopupTemplateViewId()
sets the page template to be PopupPageTemplate
.
Example 22-5 Managed Bean Code to Process Page Templates Dynamically
public class myClass { final private String MDPageTemplate = "/MDPageTemplate.jspx"; final private String PopupPageTemplate = "/PopupPageTemplate.jspx"; private String templateViewId; public myClass() { super(); templateViewId = MDPageTemplate; } public String gettemplateViewId() { return templateViewId; } public void setMDTemplateViewId(ActionEvent ae) { templateViewId = MDPageTemplate; } public void setPopupTemplateViewId(ActionEvent ae) { templateViewId = PopupPageTemplate; } }
When a page is created using a template that contains ADF data binding, the following happens:
The calling page follows the standard JSF/ADF lifecycle, as documented in Chapter 23, "Understanding the Fusion Page Lifecycle." As the page enters the Restore View phase, the URL for the calling page is sent to the binding context, which finds the corresponding page definition file.
During the Initialize Context phase, the binding container for the calling page is created based on the page definition file.
During the Prepare Model phase, the page template executable is refreshed. At this point, the binding container for the template is created based on the template's page definition file, and added to the binding context.
The lifecycle continues, with UI components and bindings from both the page and the template being processed.
Creating a web page for an application that uses ADF Model layer data binding is no different than described in the "Creating a View Page" section in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework. You can create pages either by double-clicking a view activity in a task flow or by using the New Gallery. When creating the page (or dropping a view activity onto a task flow), you can choose to create the page as a JSF JSP or as a JSF JSP fragment. JSF fragments provide a simple way to create reusable page content in a project, and are what you use when you wish to use task flows as regions on a page. When you modify a JSF page fragment, the JSF pages that consume the page fragment are automatically updated.
Note:
Although JDeveloper supports XHTML files to be used in applications that use Facelets, thefaces-config.xml
and adfc-config.xml
diagrammers do not support XHTML. In order to add navigation to these files, you have to manually edit the code by clicking the Source tab.When you begin adding content to your page, you typically use the Component Palette and Data Controls panel of JDeveloper. The Component Palette contains all the ADF Faces components needed to declaratively design your page. Once you have the basic layout components placed on the page, you can then drag and drop items from the Data Controls panel to create ADF Model databound UI components. The remaining chapters in this part of the book explain in detail the different types of databound components and pages you can create using ADF Model data binding.
Managed beans are Java classes that you register with the application using various configuration files. When the JSF application starts up, it parses these configuration files, and the beans listed within them are made available. The managed beans can be referenced in an EL expression, allowing access to the beans' properties and methods. Whenever a managed bean is referenced for the first time and it does not already exist, the Managed Bean Creation Facility instantiates the bean by calling the default constructor method on it. If any properties are also declared, they are populated with the declared default values.
Often, managed beans handle events or some manipulation of data that is best handled at the front end. For a more complete description of how managed beans are used in a standard JSF application, see the Java EE tutorial on Oracle's Technology Network web site (http://www.oracle.com/technetwork/java/javaee/overview/index.html
).
Best Practice:
Use managed beans to store logic that is related to the UI rendering only. All application data and processing should be handled by logic in the business layer of the application. Similar to how you store data-related logic in the database using PL/SQL rather than a Java class, the rule of thumb in a Fusion web application is to store business-related logic in the middle tier. This way, you can expose this logic as business service methods, which can then become accessible to the ADF Model layer and be available for data binding.In an application that uses ADF data binding and ADF task flows, managed beans are registered in different configuration files from those used for a standard JSF application. In a standard JSF application, managed beans are registered in the faces-config.xml
configuration file. In a Fusion web application, managed beans can be registered in the faces-config.xml
file, the adfc-config.xml
file, or a task flow definition file. Which configuration file you use to register a managed bean depends on what will need to access that bean, whether or not it needs to be customized at runtime, what the bean's scope is, and in what order all the beans in the application need to be instantiated. Table 22-1 describes how registering a bean in each type of configuration file affects the bean.
Note:
Registering managed beans within thefaces-config.xml
file is not recommended in a Fusion web application.
Managed beans accessed within the task flow definition must be registered in that task flow's definition file.
Table 22-1 Effects of Managed Bean Configuration Placement
Managed Bean Placement | Effect |
---|---|
|
|
Task flow definition file |
|
|
|
As a general rule for Fusion web applications, a bean that may be used in more than one page or task flow, or one that is used by pages within the main unbounded task flow (adfc-config
), should be registered in the adfc-config.xml
configuration file. A managed bean that will be used only by a specific task flow should be registered in that task flow's definition file. There should be no beans registered in the faces-config.xml
file.
Note:
If you create managed beans from dialogs within JDeveloper, the bean is registered in theadfc-config.xml
file, if it exists.For example, in the StoreFront module, the myOrdersBean
managed bean is used by the myOrders.jspx
page to handle the case where a user decides to cancel editing an order, and the edits have already been committed to the model but have not yet been persisted to the database. Because this bean is used by a page within the adfc-config
unbounded task flow, it is registered in the adfc-config.xml
file. The custRegBasicInformationBean
is a managed bean used by the basicInformation
JSF fragment to handle the selections in the shuttle component on that page. Because it is used solely within the customer-registration
task flow, it is registered in the customer-registration-task-flow
definition file.
This section describes how to create a managed bean for use within a task flow (either the default adfc-config
flow or any bounded task flow). For more information regarding managed beans and how they are used as backing beans for JSF pages, see the "Creating and Using Managed Beans" section in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.
Within the editors for a task flow definition, you can create a managed bean and register it with the JSF application at the same time.
To create a managed bean for a task flow:
In the Application Navigator, double-click either the adfc-config.xml
file or any other task flow definition file.
At the bottom of the window, click the Overview tab.
In the overview editor, click the Managed Beans navigation tab. Figure 22-2 shows the editor for the adfc-config.xml
file.
Click the Add icon to add a row to the Managed Beans table.
In the fields, enter the following:
managed-bean-name: A name for the bean.
managed-bean-class: If the corresponding class has already been created for the bean, use the browse (...) button for the managed-bean-class field to search for and select the class. If a class does not exist, enter the name you'd like to use. Be sure to include any package names as well. You can then use the drop-down menu to choose Generate Class, and the Java file will be created for you.
managed-bean-scope: The bean's scope. For more information about the different object scopes, see Section 23.3, "Object Scope Lifecycles."
Note:
When determining what scope to register a managed bean with or to store a value in, keep the following in mind:Always try to use the narrowest scope possible.
If your managed bean takes part in component binding by accepting and returning component instances (that is, if UI components on the page use the binding attribute to bind to component properties on the bean), then the managed bean must be stored in BackingBean
scope. If it can't be stored in one of those scopes (for example, if it needs to be stored in sessionScope
for high availability reasons), then instead of using component binding, you need to use the ComponentReference API. For more information, see the ”What You May Need to Know About Component Bindings and Managed Beans” section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework
Use the sessionScope
scope only for information that is relevant to the whole session, such as user or context information. Avoid using the sessionScope
scope to pass values from one page to another.
You can also set the scope to none
. While not technically a scope, none
means that the bean will not live within any particular scope, but will instead be instantiated each time it is referenced. You should set a bean's scope to none
when it is referenced by another bean.
You can optionally add needed properties for the bean. With the bean selected in the Managed Beans table, click the Add icon for the Managed Properties table. Enter a property name (other fields are optional).
Note:
While you can declare managed properties using this editor, the corresponding code is not generated on the Java class. You will need to add that code by creating private member fields of the appropriate type and then using the Generate Accessors menu item on the context menu of the source editor to generate the corresponding getter and setter methods for these bean properties.When you use the configuration editor to create a managed bean and elect to generate the Java file, JDeveloper creates a stub class with the given name and a default constructor. Example 22-6 shows the code added to the MyBean
class stored in the view package.
Example 22-6 Generated Code for a Managed Bean
package view; public class MyBean { public MyBean() { } }
You now need to add the logic required by your task flow or page. You can then refer to that logic using an EL expression that refers to the managed-bean-name
value given to the managed bean. For example, to access the myInfo
property on the bean, the EL expression would be:
#{my_bean.myInfo}
JDeveloper also adds a managed-bean
element to the appropriate task definition file. Example 22-7 shows the managed-bean
element created for the MyBean
class.
Typically, in an application that runs in a clustered environment, a portion of the application's state is serialized and copied to another server or a data store at the end of each request so that the state is available to other servers in the cluster.
Note:
If the managed bean will be callingset
and get
methods on ADF Faces components, you cannot serialize the managed beans because ADF Faces components are not serializable. You will need to access the ADF Faces components in another way. For more information, see the ”What You May Need to Know About Component Bindings and Managed Beans” section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.When you are designing an application to run in a clustered environment, you must:
Ensure that all managed beans with a lifespan longer than one request are serializable (that is, they implement the java.io.Serializable
interface). Specifically, beans stored in session scope, page flow scope, and view scope need to be serializable.
Tip:
To identify failures with objects stored in page flow scope and view scope, usewriteObject()
. This method provides additional information in an exception about the object and scope that failed to serialize. Additional information might be a region's page flow scope and the key of the object.Make sure that the framework is aware of changes to managed beans stored in ADF scopes (view scope and page flow scope).
When a value within a managed bean in either view scope or page flow scope is modified, the application needs to notify the framework so that it can ensure that the bean's new value is replicated.
In Example 22-8, an attribute of an object in view scope is modified.
Example 22-8 Code That Modifies an Object in viewScope
Map<String, Object> viewScope = AdfFacesContext.getCurrentInstance().getViewScope(); MyObject obj = (MyObject)viewScope.get("myObjectName"); Obj.setFoo("newValue");
Without additional code, the framework will be unaware of this change and it will not know that a new value needs to be replicated within the cluster. To inform the framework that an object in an ADF scope has been modified and that replication is needed, use the markScopeDirty()
method, as shown in Example 22-9. The markScopeDirty()
method accepts only viewScope
and pageFlowScope
as parameters.
Example 22-9 Additional Code to Notify Oracle ADF of Changes to an Object
ControllerContext ctx = ControllerContext.getInstance(); ctx.markScopeDirty(viewScope);
This code is needed for any request that modifies an existing object in one of the ADF scopes. If the scope itself is modified by the scope's put()
, remove()
, or clear()
methods, it is not necessary to notify the framework.
If an application is not deployed to a clustered environment, the tracking of changes to ADF memory scopes is not needed, and by default, this functionality is disabled. To enable ADF Controller to track changes to ADF memory scopes and replicate the page flow scope and view scope within the server cluster, set the <adf-scope-ha-support>
parameter in the adf-config.xml
file to true
. Because scope replication has a small performance overhead, it should be enabled only for applications running in a server-cluster environment.
Example 22-10 shows adf-scope-ha-support
set to true
in the adf-config.xml
file.
Example 22-10 adf-scope-ha-support Parameter in the adf-config.xml File
<?xml version="1.0" encoding="US-ASCII" ?> <adf-config xmlns="http://xmlns.oracle.com/adf/config" xmlns:adfc="http://xmlns.oracle.com/adf/controller/config"> <adfc:adf-controller-config> ... <adfc:adf-scope-ha-support>true</adfc:adf-scope-ha-support> ... </adfc:adf-controller-config> ... </adf-config>