Tuesday, May 11, 2010

openSubTask and closeSubTask APIs

openSubTask and openMainTask seem to be related and have similar parameter lists. However, they behave differently and are used for different purposes. This article examines what openSubTask and closeSubTask does in details.

In a nutshell, openSubTask and closeSubTask APIs are programmatic support in Oracle Applications Core to notify recent items about a sub-flow launch.

Recent Items and Favorites[1]

Recent Items in Oracle Fusion Web Applications tracks a list of the last 20 task flows visited by a user. The Recent Items list is persistent across user sessions and a task can be relaunched from the Recent Items list.

The Favorites menu is implemented on top of Recent Items. Any current task on the Recent Items list can be bookmarked and placed in Favorites' folders.

openMainTask and closeMainTask


Both openMainTask and openSubTask (or their close counterparts) are provided on FndUIShellController [2]data control. At design time, you can drag and drop both operations to UI components (for example, your page fragments) to create needed bindings objects in XML meta data files:



openMainTask is used to open a new Task in the Main Area of Oracle Fusion Web Applications that use UIShell templates[5]. Besides opening a new tab, openMainTask also pushes a new Task Flow History object onto a stack, which is used to keep track of all task flows that have been opened. The Task Flow ID and its associated parameter values are encapsulated in the Task Flow History object.

Having this information, the call to closeMainTask pops the stack to get the last Task Flow ID and its parameter values that were displayed, and re-initializes the Main Area with that Task Flow and parameter information.

Sub-Flow

When a task flow is called from the local area task flow via task flow call activity, it is called a 'sub-flow'. By default, subflows will not be recorded on the stack as described above. Two new APIs[3] are exposed in FndUIShellController[2] data control for registering sub-flows:
  • openSubTask
  • closeSubTask.

openSubTask and closeSubTask

When openSubTask is called before a sub-flow is launched, sub-flow ID and its parameter values are pushed onto the stack. Besides that, Applications Core implementation also notifies Recent Items & Favorites[1] (or RI & Favs) implementation with recorded task flow information. Once tasks are recorded on the Recent Items list, they are also eligible for Favorites.
This essentially makes a sub-flow bookmarkable by RI & Favs and can be launched directly from the selection of menu items on Recent Items.
When a sub flow finishes execution, it should call closeSubTask on all of its exit paths. What closeSubTask API does is:
if topOfStack is SUB_FLOW type {
  Pop it from the stack;
  Notify RI&Favs for the new topOfStack entry;
} else {
  Look inside the stack to find a match based on sub flow ID and its keyList;
  if (found the first one) {
    Remove it from the Stack;
    Notify RI&Favs for the new topOfStack entry;
  }
}
Contextual events are fired when openSubTask or closeSubTask excute. The method outcome (i.e., sub-flow information encapsulated in FndMethodParameters) is delivered as the contextual event payload.
For openSubTask, an FND_OPEN_SUB_TASK event is fired and the event consumer is handleOpenSubTaskEvent method on the MainAreaHandler object.
Similarly, a FND_CLOSE_SUB_TASK event is fired when closeSubTask method executes and the event consumer is handleCloseSubTaskEvent method on the MainAreaHandler object. The main functionality of openSubTask and closeSubTask from the Applications Core side are both implemented in these event handlers.
When RI & Favs is notified with a new task flow, it does the following:
if user session (i.e., FND session) is not enabled or user is anonymous {
  do nothing and return;
}
if any of the following is not set, do nothing and return:
  Task flow ID
  Task flow label
  Task flow view ID
  Task flow webApp name
if an existing task flow on the RI list matches the new task flow based on the following condition:
  Same Task flow ID
  Same Task flow label
  Same Task flow view ID
  Same webApp name
  Same reuseInstance value
  Same keyList
then
Remove it from the list and move it to the top and update its information with new entry
else
  Add a new task flow history object to the list

Hope this article can help Oracle Fusion Developers to understand more on the functionality of Recent Items and Favorites within Oracle Fusion Web Applications. However, the details provided here are based on author's own understanding of Recent Items and Favorites implementation. These implementation details may evolve over time and there is no guarantee that they will remain valid in the future.

References

  1. Implementing Recent Items
  2. FndUIShellController
  3. openSubTask and closeSubTask
  4. openMainTask
  5. Implementing the UI Shell
  6. Oracle ADF Task Flow in a Nutshell

Monday, May 10, 2010

Action Bindings and Method Bindings in Oracle ADF 11g

PageDef.xml is the page definition XML file. It associates web page UI components with data, or data controls. Oracle JDeveloper creates this file each time you design a new web page using the Data Controls Panel or Structure window. These XML files contain the meta data used to create the bindings that populate the data in the web page’s UI components. For every web page that refers to an ADF binding, there must be a corresponding page definition file with binding definitions.

In the overview editor for any page definition’s Bindings and Executables tab, click the Add icon in the Bindings section. From the Insert Item dialog, you're allowed to choose either action or methodAction binding object to create as shown below:
The description for the action item is "Binding for Action." So, it is named action binding. The description for the methodAction item is "Method binding for the Control." It is also known as method binding. In this article, we'll examine what're the differences and similarities of these two binding objects.

Acronyms

  1. ADFm: ADF Model layer
  2. ADFc: ADF Controller
  3. ADFv: ADF View layer
  4. EL: Expression Language

Action Binding

Action binding object can be used to bind command components, such as buttons or links, to built-in data control operations (such as Commit or Rollback) or to built-in collection-level operations (such as Create, Delete, Next, Previous, or ExecuteWithParams).

Action binding is defined in the page definition using the following attributes:




































Attributes
Attribute
Description
Action

Fully qualified package name. Identifies the class for which the data control is created. In the case of the EJB session facade, this is the session bean.

BindingClass

This is for backward compatibility to indicate which class implements the runtime for this binding definition. This is used by earlier versions of
JDeveloper.

DataControl

Name of the DataControl usage in the bindingContext (.cpx) which this iteratorBinding or actionBinding is associated with.

Execute

Used by default when you drop an operation from the Data Controls Panel in the automatically configured ActionListener property. It results in executing the action binding's operation at runtime.

InstanceName

Specifies the instance name for the action.

IterBinding

Specifies the iteratorBinding instance in this bindingContainer to which this binding is associated.

Outcome

Use if you want to use the result of a method action binding (once converted to a String) as a JSF navigation outcome name.


For example, ExecuteWithParams (i.e., a built-in collection-level operation) is defined in a page definition file as:
<bindings>
<action IterBinding="TestTrendIterator" id="ExecuteWithParams"
RequiresUpdateModel="true" Action="executeWithParams">
<NamedData NDName="TSBegin" NDType="java.sql.Date"
NDValue="${bindings.ExecuteWithParams_TSBegin}"/>
<NamedData NDName="TSEnd" NDType="java.sql.Date"
NDValue="${bindings.ExecuteWithParams_TSEnd}"/>
</action>
</bindings>

Note that ExecuteWithParams on our view object (not shown here) takes two parameters:
  1. TSBegin
  2. TSEnd
These two parameters are defined to be optional (i.e., NDOption="optional") by default. This means that if you didn't provide new values programmatically at runtime, their values will be taken from meta data (i.e., ${bindings.ExecuteWithParams_TSXxx}) as provided in the action binding. See this article, for the descriptions of binding model parameter options (i.e., NDOption).

Method Binding

Method bindings are similar to action bindings. But, they are used to bind to methods defined in an ADF BC application, view object, or view row client interfaces.

Method binding is defined in the page definition using the following attributes:

























































Attributes
Attribute
Description
Action

Fully qualified package name. Identifies the class for which the data control is created. In the case of the EJB session facade, this is the session bean.

BindingClass

This is for backward compatibility to indicate which class implements the runtime for this binding definition. This is used by earlier versions of
JDeveloper.

ClassName

This is the class to which the method being invoked belongs.

DataControl

Name of the DataControl usage in the bindingContext (.cpx) which this methodAction is associated with.

DefClass

Used internally by ADF.

id

Unique identifier. May be referenced by any ADF action binding.

InstanceName

A dot-separated EL path to a Java object instance on which the associated method is to be invoked.

IsLocalObjectReference

Set to true if the instanceName contains an EL path relative to this bindingContainer.

IsViewObjectMethod

Set to true if the instanceName contains an instance path relative to the associated data control's application module.

MethodNameIndicates the name of the operation on the given instance or class that needs to be invoked for this methodActionBinding.
RequiresUpdateModelWhether this action requires that the model be updated
before the action is to be invoked.
ReturnNameThe EL path of the result returned by the associated method.

For example, myCustomMethod defined in an ADF BC application is defined to be:
<bindings>
<methodAction id="myCustomMethod"
InstanceName="SelTestPortalAMDataControl.dataProvider"
DataControl="SelTestPortalAMDataControl"
RequiresUpdateModel="true" Action="invokeMethod"
MethodName="refreshTotalComments" IsViewObjectMethod="false"/>
</bindings>

How to Access Action/Method Bindings in an Fusion Web Application

When working with Fusion web applications using the ADF Model layer for data binding, JDeveloper configures a servlet filter in your user interface project 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.

No matter what a binding object is (i.e., action binding or method binding), they are retrieved and invoked in the same way when accessed from Fusion Web Applications:
  • Retrieve them from the DCBindingContainer (i.e., the runtime object that embodies the meta data defined in the page definition) by naming an action binding or method binding.
Method bindings such as myCustomMethod, or action bindings such as Next, Previous or ExectureWithParams, exposed on a view object are instance of JUCtrlActionBinding that can be cast to the OperationBinding interface when accessed from Java:
BindingContext context = BindingContext.getCurrent();
DCBindingContainer bindingContainer = (DCBindingContainer) context.getCurrentBindingsEntry();
OperationBinding oper = bindingContainer.getOperationBinding("openSubTask");
...
oper.execute();

FacesCtrlAttrsBinding


Internally JUCtrlActionBinding is an FacesCtrlActionBinding, which is the class that connects ADFv[1] command components to ADFc[2]/ADFm[3]. Like other ADFv binding classes, this is a sub-class of an ADFm class. And like other ADFm bindings there is an entry in the pageDef.xml file for this binding (i.e., action or method binding). If the method has either parameters or a return, there will be additional attribute bindings corresponding to the parameter and return values. These attribute bindings will correspond to a FacesCtrlAttrsBinding class and be in the pageDef.xml file.

The ADFv command components that use this class are:
  • commandLink
  • commandButton,
  • commandMenuItem
  • commandToobarButton
  • commandImageLink.
and they are linked to this class via EL[4] on the component, typically the actionListener attribute.

Learn More
  1. Implement Contextual Events
  2. Oracle ADF Model In Depth
  3. Oracle ADF BindingContext and BindingContainer
  4. Open Source sample applications for Oracle Fusion Middleware technology
  5. How-To Access ADF application module with ADF faces (see Steve Muench's comments)

Monday, May 3, 2010

Oracle ADF BindingContext and BindingContainer

The Oracle ADF binding context is a runtime map (accessible through the EL expression #{data}) of all data controls and page definitions within the application. The binding context does not contain real live instances of these objects. Instead, the map contains references that become data control or binding container objects on demand. The ADF lifecycle creates the binding context from the application module, DataBindings.cpx, and page definition files.

In Oracle ADF, the group of bindings supporting the UI components on a page are described in a page-specific XML file called the page definition file. The ADF Model layer uses this file at runtime to instantiate the page’s bindings. These bindings are held in a request-scoped map called the binding container, accessible during each page request using the EL expression:
  #{bindings}

This expression always evaluates to the binding container for the current page. For example, to access the collectionModel of binding object named MyShoppingCart , you use the EL expression:
  #{bindings.MyShoppingCart.collectionModel}

BindingContext

The binding context lives in the HttpSession for each end user. It holds references to lightweight application module data control objects that manage acquiring an application module instance from the pool during the request (when the data control is accessed) and releasing it to the pool at the end of each request. The data control holds a reference to the ADF session cookie that identifies the user session. The binding context also holds references to binding containers. The binding context might contain many data controls and many binding containers.

There are three options to access the binding context at runtime by Fusion Web Applications:
  1. BindingContext.getCurrent()
  2. BindingUtils.getBindingContext()
  3. JsfUtils.resolveExpression("#{data}")
For option 1 and 2, they are implemented in the same way internally:
  import oracle.adf.model.BindingContext;

  (BindingContext)ADFContext.getCurrent().getSessionScope().get("data");
However, option 3 is different and resolveExpression() is defined to be:
public static Object resolveExpression(String expression) {
FacesContext facesContext = getFacesContext();
Application app = facesContext.getApplication();
ExpressionFactory elFactory = app.getExpressionFactory();
ELContext elContext = facesContext.getELContext();
ValueExpression valueExp =
elFactory.createValueExpression(elContext, expression,
                     Object.class);
return valueExp.getValue(elContext);
}

As you can see it, the third approach is more expensive because it involves extra expression parsing and syntactic validation of the expression.

BindingContext is an object that implements the Map interface and exposes generic methods to access the binding layer. For example, to find a data control, you could use the findDataControl()method on BindingContext
  findDataControl(dc_name)


BindingContainer

To access binding container, you first retrieve binding context as described above; then you use binding context's getCurrentBindingsEntry method to retrieve binding container object:
  import oracle.binding.BindingContainer;

  BindingContainer bc = bindingContext.getCurrentBindingsEntry();
Internally, getCurrentBindingsEntry() is implemented as follows:
  (BindingContainer)ADFContext.getCurrent().getRequestScope().get("bindings");

If you use option 3 as described above, you can retrieve binding container in a more straightforward way (although it's still more expensive):
FacesContext facesContext = FacesContext.getCurrentInstance();
ExpressionFactory exp = facesContext.getApplication().getExpressionFactory();
DCBindingContainer bindingContainer =
(DCBindingContainer)exp.createValueExpression(facesContext.getELContext(),
"#{bindings}",DCBindingContainer.class).getValue(facesContext.getELContext());

Fusion application developers who prefer working with type-safe methods can cast the bindings instance (i.e., BindingContainer) to DCBindingContainer:

DCBindingContainer object exposes more methods than the its super class object BindingContainer. For example, you can access the application module's client interface from this DCBindingContainer by naming an ADF action binding or an ADF iterator binding as shown below:
// 1. Access the binding container
DCBindingContainer bc = (DCBindingContainer)getBindings();
// 2. Find a named action binding
JUCtrlActionBinding action =
(JUCtrlActionBinding)bc.findCtrlBinding("SomeActionBinding");
// 3. Get the data control from the iterator binding (or method binding)
DCDataControl dc = action.getDataControl();
// 4. Access the data control's application module data provider
ApplicationModule am = (ApplicationModule)dc.getDataProvider();
// 5. Cast the AM to call methods on the custom client interface
StoreServiceAM service = (StoreServiceAM)am;
// 6. Call a method on the client interface
service.doSomethingInteresting();

Final Words

In this article, we have demonstrated how bindings can be accessed via Java code. However, this should be done only as appropriate. In other words, use it when attribute or executable binding properties at JDeveloper's designtime are not able to declaratively meet the needs of the application.

References

  1. Oracle Fusion Developer Guide by Frank Nimphius and Lynn Munsinger
  2. Oracle Fusion Applications Developer's Guide 11g