Cross Column

Showing posts with label Managed Bean. Show all posts
Showing posts with label Managed Bean. Show all posts

Sunday, May 1, 2011

Invoking Application Module Custom Methods from Oracle ADF Frontend—Why and How?

In an Oracle Fusion web application, you should use managed beans[4] 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.

In this article, we'll show how to refresh a calculated attribute[6] named Total Comments after user adds a new comment using Create Comment Dialog. As noted above, refreshing Total Comments should be handled in ADF backend (i.e., ADF Business Components), not ADF frontend (i.e., ADF Faces). Note that ADF backend refers to Model project and ADF frontend refers to ViewController project in a Fusion web application.

Background Information

In the described application, we have two view objects (i.e., TestVO and TestCommentVO) with master-detail relationship. "TotalComments" on the TestVO is a calculated attribute which computes total number of chronological comments (represented by TestCommentVO) added to a test.

On the Test View page, it displays Total Comments column which is also a link. By clicking on the link, user can navigate to the Test Comment page. On the Test Comment page, user is allowed to add new comments. After adding new comments, the Total Comments column on the original Test View page need to reflect the new total.



The Task

To achieve this task, we need to invoke a custom method implemented in ADF Business Components from the Test Comment component implemented in ADF Faces. Method invokation is triggered when user clicks the Save and Close button to save the newly created comment.
The bridge provided between ADF frontend and ADF backend is the Data Binding Layer in Fusion web application[3]. ADF data-binding layer implements the Data Controls and Bindings from JSR-227. The data controls abstract the back-end business service implementations and binding objects link front-end user interface controls in a declarative way to back-end data.

The steps of the task ordered from backend (in blue) to frontend (in black) are summarized here:
  1. Creating a custom method named refreshTotalComments in the application module Class (i.e., SelTestPortalAMImpl.java).
  2. Exporting refreshTotalComments by including the method on the application module's UI client interface.
  3. Adding a new action binding[5] named refreshTotalComments on TestCommentPageDef.xml.
  4. Creating a managed bean named TestCommentBean.java with a method action named saveAndClose. In the method, it will retrieve and execute refreshTotalComments operation binding.
  5. Registering new managed bean in adc-config.xml with the scope of request.
  6. Linking method action saveAndClose on the managed bean to the actionlistener of Save and Close button.
In the following sections, we'll describe those steps in details.

Step 1 — Adding Custom Method to the AppModuleImpl File

To add a custom service method (i.e., refreshTotalComments) to your application module, you must generate the application module class files first.

To generate Java files for your application module class:
  1. In the Application Navigator, double-click the application module.
  2. In the overview editor, click the Java navigation tab and click the Edit java options button.
  3. In the Select Java Options dialog, select Generate Application Module Class.
  4. Click OK.

In SelTestPortalAMImpl.java file, you add your custom service method — refreshTotalComments. Here we have left out the details of refreshTotalComments. For ADF developers need to write a custom method such as refreshTotalComments, you can read this document. It provides a high-level description of the key ADF Business Components classes in the Oracle Application Development Framework and it summarizes the methods that ADF developers write, call, and override most frequently.

Step 2 — Publishing Custom Method on the Application Module’s Client Interface

To include a public method from your application module's custom Java class on the client interface, use the Java Classes page of the overview editor for the application module, and then click the Edit icon in the Client Interface section of the page to display the Edit Client Interface dialog. Select method refreshTotalComments from the Available list and click the Add button to shuttle them into the Selected list. Then click OK to close the editor.


You can include any custom method in the client interface that obeys these implementation rules:
  • If the method has a non-void return type, the type must be serializable (i.e., implements the java.io.Serializable interface).
  • If the method accepts any parameters, all their types must be serializable.
  • If the method signature includes a throws clause, the exception must be an instance of JboException in the oracle.jbo package.

Step 3 — Adding a New Action Binding

In the ViewController project, select Test Comment page and right click it. From the context menu, select "Go to Page Definition." This will bring you to the TestCommentPageDef.xml.

In the Overview editor for the Test Comment page definition’s Bindings and Executables tab, click the Add icon in the Bindings section. Then, follow these steps:
  1. In the Insert Item dialog, select methodAction and click OK.
  2. In the Create Action Binding dialog:
    • Select the data collection (i.e., SelTestPortalAMDataControl) where you have created your handler.
    • From the Operation dropdown list, select the handler (i.e., refreshTotalComments).
    • Click OK.



Step 4 — Creating a New Managed Bean

In the ViewController project, create a managed bean named TestCommentBean.java with a method action named saveAndClose as shown below.
public void saveAndClose(ActionEvent actionEvent) {
try{
// Commit the transaction
OperationBinding  oper = getOperBindings("Commit");
oper.execute();
// refresh total comments
oper = getOperBindings("refreshTotalComments");
oper.execute();
}catch(Exception e){
e.printStackTrace();
}
}
/**
* This methos returns the operation bindings of the passed method name
* @param operation name
* @return
*/
private OperationBinding getOperBindings(String operation) throws Exception
{
OperationBinding oper=null;

try
{
FacesContext facesContext = FacesContext.getCurrentInstance();
ExpressionFactory exp = facesContext.getApplication().getExpressionFactory();
DCBindingContainer bindingContainer =
(DCBindingContainer) exp.createValueExpression(facesContext.getELContext(),
                                      "#{bindings}",
                                       DCBindingContainer.class).getValue(facesContext.getELContext());
// A ControlBinding that binds an datacontrol action, including navigational
// actions such as "Next" and "Prev", or other actions such as "Commit" and
// "Rollback", to a view component.
oper = bindingContainer.getOperationBinding(operation);
}
catch(Exception e)
{
e.printStackTrace();
}
return oper;
} //end getOperBindings

As shown in the code, we need to retrieve two operation bindings (i.e., Commit and refreshTotalComments) from the binding container[7]. Operation binding refreshTotalComments is used at runtime to invoke our Application Module custom method.

Step 5 — Registering New Managed Bean in adc-config.xml

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.

To register TotalCommentBean in adc-config.xml, do the following:
  1. In the Application Navigator, double-click the adfc-config.xml file in theWEB-INF folder.
  2. In the editor window for the adfc-config.xml file, click the Overview tab.
  3. In the Managed Beans page, in the Managed Beans section click the Add icon and enter TotalCommentBean as the name of the bean, enter the fully qualified class name, and select request scope[8].

Step 6 — Linking Method Action to the ActionListener of Button

The final step is to link method action saveAndClose on the managed bean to the actionListener of Save and Close button as shown below:
<af:commandbutton id="FAsc1"
textandaccesskey="#{applcoreBundle.SAVE_AND_CLOSE}"
shortdesc="#{applcoreBundle.SAVE_AND_CLOSE_SHORT_DESC}"
actionlistener="#{TestCommentBean.saveAndClose}">
</af:commandbutton>
Note that you can achieve this linking declaratively using Property Inspector.

The Explanation

An application module can expose its data model of view objects to clients without requiring any custom Java code. This allows client code to use the ApplicationModule, ViewObject, RowSet, and Row interfaces in the oracle.jbo package to work directly with any view object in the data model.

Whenever there is a need to provide custom codes as shown in our sample application, you should encapsulate the details by writing a custom method in your application module's Java class.

When working with Fusion web applications using the ADF Model layer for data binding, JDeveloper configures a servlet filter in your user interface project (i.e., ViewController) called the ADFBindingFilter. It orchestrates the automatic acquisition and release of an appropriate application module instance based on declarative binding metadata, and ensures that the service is available to be looked up as a data control using a known action binding or iterator binding, specified by any page definition file in the user interface project.

At runtime, you can access the application module's client interface from the DCBindingContainer by naming an ADF action binding or an ADF iterator binding (see step 4). You can also reference the binding context[7] and call methods on the custom client interface in any JSF managed bean.

Reference(s)

  1. Most Commonly Used Methods in ADF Business Components
  2. A detailed look at Binding Model Parameter Options (NDOption)
  3. Oracle ADF Model In Depth
  4. Managed Beans in Oracle Fusion Web Applications
  5. Action Bindings and Method Bindings in Oracle ADF 11g
  6. Examining View Object Attributes in Oracle ADF 11g
  7. Oracle ADF BindingContext and BindingContainer
  8. Types of Memory Scopes in Fusion Web Applications
  9. Oracle Fusion Developer Guide: Building Rich Internet Applications with Oracle ADF Business Components and Oracle ADF Faces
  10. Open Source sample applications for Oracle Fusion Middleware technology
  11. Using Bind Variable to Implement Range Selection Declaratively (Xml and More)
  12. Book Review: Developing Web Applications with Oracle ADF Essentials (Xml and More)

Monday, November 30, 2009

Managed Beans in Oracle Fusion Web Applications

In JDeveloper, it helps you create different types of applications using various templates. One of these templates is the Fusion Web Application (ADF) template, which provides the correctly configured set of projects you need to create a web application that uses ADF Faces for the view, ADF Controller for the controller, and ADF Business Components for business services. When you create an application using this template, JDeveloper automatically creates the JSF and ADF configuration files needed for the application.


Oracle ADF framework is a container in the sense that it contains and manages the lifecycle and configuration of application objects. In the ADF framework, you can declare how each of your application objects should be created, how they should be configured, and how they should be associated with each other.

Managed Beans

A managed bean - sometimes simply referred to as an MBean - is a type of JavaBean, created with dependency injection and registered with the application using various configuration files. Managed Beans are particularly used in the Java Management Extensions technology. But with Java EE 6, the specification provides for a more detailed meaning of a managed bean.

The MBean represents a resource running in the Java virtual machine, such as an application or a Java EE technical service (transactional monitor, JDBC driver, etc.). They can be used for getting and setting applications configuration (pull), for collecting statistics (pull) (e.g. performance, resources usage, problems) and notifying events (push) (e.g. faults, state changes).

Backing beans are managed beans that contain logic and properties for UI components on a JSF page. In a standard JSF application, managed beans are registered in the faces-config.xml configuration file.

Three characteristics of a managed bean:
  • Name — way to reference bean in JSF application
  • Class — fully qualified class name of bean
  • Scope — how long the bean will live (i.e., application, session, request)

The managed-bean element can contain zero or more managed-property elements (see example below), each corresponding to a property defined in the bean class. These elements are used to initialize the values of the bean properties. If you don’t want a particular property initialized with a value when the bean is instantiated, do not include a managed-property definition for it in your application configuration resource file. Read this article to learn how to use the managed-property element.

Dependency Injection

The key benefit of Dependency Injection (DI) is loose coupling. When applying DI, objects are given their dependencies at creation time by some external entity that coordinates each object in the system. In other words, dependencies are injected into objects. So, DI means an inversion of responsibility with regard to how an object obtains references to collaborating objects. With DI, your application objects are freed from the burden of fetching their own dependencies and are able to focus on their tasks, trusting that their dependencies will be available when needed.

JavaServer Faces Managed Bean Facility

In this article, it discusses JavaServer Faces Managed Bean Facility which is provided similarly in the ADF framework. In summary, it provides the following functionalities:

  • Control of instantiation (constructor) and setter based injection of managed objects
  • Control when objects are loaded (i.e., eager instantiation vs. lazy loading)
  • Dependency Handling
  • Lifecycle Support
  • Configuration Support

Managed Beans in Fusion Web Applications

The controller used in ADF framework is ADF Controller (ADFc). It is an extension to JSF page flow engine. It allows the definition of managed beans with additional memory scopes[5]:
  • Application scope
  • Session scope
  • Page flow scope
  • Request scope
  • Backing bean scope
  • View scope
In a Fusion web application, managed beans can be registered in:
  • faces-config.xml file
  • adfc-config.xml file
  • task flow definition file[6]
However, registering managed beans within the faces-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. 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. For example, a managed bean named updateUserInfoBean is registered in adfc-config.xml below:
<?xml version="1.0" encoding="windows-1252" ?>
<adfc-config xmlns="http://xmlns.oracle.com/adf/controller" version="1.2">
 <view id="TestPage">
   <page>/TestPage.jspx</page>
 </view>
 <view id="Messages">
   <page>/ui/page/Messages.jspx</page>
 </view>
  <managed-bean>
    <managed-bean-name>updateUserInfoBean</managed-bean-name>
    <managed-bean-class>oracle.fodemo.storefront.account.view.managed.UpdateUserInfoBean</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
    <managed-property>
      <property-name>allItemsIteratorName</property-name>
      <value>AvailableCategoriesShuttleListIterator</value>
    </managed-property>
    <managed-property>
      <property-name>allItemsValueAttrName</property-name>
      <value>CategoryId</value>
    </managed-property>    <managed-property>
      <property-name>allItemsDisplayAttrName</property-name>
      <value>CategoryName</value>
    </managed-property>
    <managed-property>
      <property-name>allItemsDescriptionAttrName</property-name>
      <value>CategoryDescription</value>
    </managed-property>
    <managed-property>
      <property-name>selectedValuesIteratorName</property-name>
      <value>CustomerInterestsIterator</value>
    </managed-property>
    <managed-property>
      <property-name>selectedValuesValueAttrName</property-name>
      <value>CategoryId</value>
    </managed-property>
    <managed-property>
      <property-name>addressTable</property-name>
      <property-class>oracle.adf.view.rich.component.rich.data.RichTable</property-class>
      <value></value>
    </managed-property>
  </managed-bean>
</adfc-config>

You can also find another managed bean example in this article. Finally, in a Fusion web application, you should 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.

More Reading...


  1. Creating and Using Managed Beans (if you use ADF Faces components in a standard JSF application)
  2. Using a Managed Bean in a Fusion Web Application (if you use Oracle ADF Model data binding and ADF Controller)
  3. JavaServer Faces (JSF) Tutorial
  4. Backing Bean in JSF Tutorial
  5. Types of Memory Scopes in Fusion Web Application
  6. Oracle ADF Task Flow in a Nutshell
  7. Using a Managed Bean in a Fusion Web Application

Tuesday, October 20, 2009

Types of Memory Scopes in Fusion Web Applications

At runtime, ADF objects such as the binding container and managed beans are instantiated. Each of these objects has a defined lifespan set by its scope attribute. Different scopes have different durations. The wider the scope, the higher availability of an object. When determining what scope to register a managed bean with, always try to use the narrowest scope possible.


6 Types of Memory Scopes

There are six types of memory scopes in a Fusion web application:


  • Application scope: An application scope object is available for the duration of the application and is shared among users. This scope may be used to hold static objects that are the same for all users.

  • Session scope: The object is available for the duration of the session, which is user instance-specific. A use case for a session scope bean is a user info bean that stores information about a user, which is read from the database or an LDAP server, to avoid unnecessary queries.

  • Page flow scope: A pageFlow scope exists for each task flow instance and has a lifespan between request and session scope. The lifetime of the scope spans across all pages in a bounded task flow.

  • Request scope: The object is available from the time an HTTP request is made until a response is sent back to the client. From another perspective, a request scope starts with a request to be issued from one view to another for navigation cases that don't perform a redirect but a default server-side forward. The scope spans across all non-view activities that follow the view of interest to the next view activity.

  • Backing bean scope: The backing bean scope is comparable to the request scope, with the difference in that it exists for a specific client component. In general, all managed beans used in reusable components should be configured to backingBean scope. For example, bounded task flows that are designed to be regions on a page should use the backingBean scope if more than one instance of the task flow is expected to be on a single page.

  • View scope: The object is available until the view ID for the current view activity changes. This becomes handy when you use partial page rendering. If you have a dependent list box, you might send a server request to refresh the list box. When a response is returned, the request scope will be gone but the view scope will be still there. Therefore, view scope can be used to store data when partial rendering request comes back. The view scope exists not only for views that are rendered by JSPX pages, but also for views rendered by page fragments, as is the case in task flows that are built to execute in a region. The view scope of the parent page is not accessible from components added to a page fragement in a region, and the view scope of a view in a region is not accessible for the parent page.
Some scopes are window-specific and some not. For example, there is no window uniqueness for session scope, all windows in the session share the same session scope instance. On the other hand, page flow or view scope are window-specific.

When you create objects (such as a managed bean) that require you to define a scope, you can set the scope to none, meaning that it 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.

Note that page flow, backing bean, and view scope are not standard JSF scopes. You access objects in those scopes (under the hood they're java.util.Map's) via expression language with scope qualification. For instance, to reference the MyBean managed bean from pageFlowScope scope, your expression would be #{pageFlowScope.MyBean}.



A Managed Bean Example

In this tutorial provided by Frank Nimphius, it demonstrates the usage of a request-scoped managed bean (i.e., HandleCaptchaBean) which is defined in adfc-config.xml file:
<adfc-config xmlns="http://xmlns.oracle.com/adf/controller" version="1.2">
<managed-bean>
<managed-bean-name>HandleCaptchaBean</managed-bean-name>
<managed-bean-class>adf.sample.HandleCaptchBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
</adfc-config>

At runtime, when user enters the challenged text and hit the try button, a method verifyAnswer defined on the managed bean would be invoked. The definition of the button looks like this:
<af:commandButton text="try" id="cb1"
actionListener="#{HandleCaptchaBean.verifyAnswer}"
partialSubmit="true" immediate="false"/>
The text entered by the user would set a request-scoped attribute (i.e., bestGuess) as follows:
<af:inputText id="it1" value="#{requestScope.bestGuess}"/>
When the action listener verifyAnswer is executed, it would fetch the request-scoped attribute bestGuess in this way:

FacesContext fctx = FacesContext.getCurrentInstance();
ExternalContext ectx = fctx.getExternalContext();
String answer = (String) ectx.getRequestMap().get("bestGuess");

Then fetched text is compared against the correct answer to see if the user is either a human or a robot.



ADF Task Flow

A task flow consists of activities and control flow cases that define the transitions between activities. Control flow rules are based on JSF navigation rules, but capture additional information. JSF navigation is always between pages, whereas control flow rules describe transitions between activities.



In the Figure, an unbounded task flow consists of a view activity, a router activity, a method call activity, a view activity, a bounded task flow, and a view activity and control flows in that order. There is one private scope per task flow, which is called page flow scope. When the outer task flow is executed, a new page flow scope PSF1 is created for it. When you enter the inner task flow, another page flow scope (i.e., PSF2) is created and PSF1 is suspended. After you exit from the inner task flow, PSF1 of the outer task flow is resumed. A task flow stack is maintained to keep track of the calls from task flow to task flow. An ADF Unbounded Task Flow always logically exists as the first entry on the task flow stack but would simply be empty.

When determining what scope to use for variables within a task flow, you should use any of the scope options other than application or session scope. These two scopes will persist objects in memory beyond the life of the task flow and therefore compromise the encapsulation and reusable aspects of a task flow. In addition, application and session scopes may keep objects in memory longer than needed, causing unneeded overhead.

Reusable components, especially those that are added with multiple instances on a single page, should be bound to per instance scope such as pageFlowScope, viewScope, or backingBean scope. If they are bound to broader scoped beans, many problems could ensue.

When you need to pass data values between activities within a task flow, you should use page flow scope. View scope is recommended for variables that are needed only within the current view activity, not across view activities. Request scope should be used when the scope does not need to persist longer than the current request. Lastly, backing bean scope must be used for backing beans in your task flow if there is a possibility that your task flow will appear in two region components or declarative components on the same page and you would like to achieve region instance isolation.


References



  1. Oracle Fusion Developer Guide by Frank Nimphius and Lynn Munsinger

  2. Creating and Using Managed Beans (if you use ADF Faces components in a standard JSF application)

  3. Using a Managed Bean in a Fusion Web Application (if you use Oracle ADF Model data binding and ADF Controller)

  4. JavaServer Faces (JSF) Tutorial

  5. Backing Bean in JSF Tutorial

  6. Managed Beans in Oracle Fusion Web Applications