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)

4 comments:

Unknown said...

Hi,
Could you please send the code for it. I have similar issue. I have calculated attributes in my view object. I dragged and dropped that as an ADF:Tree. Below that tree I dragged and dropped the same view object as form, this is for editing and saving the data. But, the calculated attributes fields in tha above adf:table are not getting resfreshed. But, the data is getting saved into the back end. So how can refresh these calculated attribute.

ADF OAF Tech said...

Hi,

Gr8 Post. Could you please explain how to execute Application module method from same listner which returns int/string or array ?

Thanks,
Jit

Florin Marcus said...

Hi Stanley,
Two remarks regarding this post:

1. The recommended way to access the Binding Container is:

http://blogs.oracle.com/jdevotnharvest/entry/best_practice_invoking_business_services

Doesn't make sense to hard-code it by going through EL API. Is slower too.


2. The try/catch blocks not useful, if you want to catch any business exception thrown from your customMethods. But probably you are trying to get unexpected exceptions only.

I am a fan of your weblogic posts though,
Florin

Jajang Nurjaman said...

Your blog is really informative and is also written in well mannered. Thanks for sharing this knowledge with us. I enjoyed reading it. If you looking for
Best Badminton Racket in 2022
You can visit our website.