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

6 comments:

家祥皇雯 said...

Thx ur share........................................

宥妃 said...

Unable to give you a heart. so have a reply to push up your post. ........................................

BokHaile8854 said...

喘口氣,看個文章,謝謝您的格子囉~~ ........................................

sai_explorer said...

Hi ,

Your blog on ADF binding context is very informative. I have a doubt in this area.
If I want to evaluate an expression like this "#{bindings.allEmployees1.treeModel.makeCurrent}"

How can I do it If I follow your method 1 and method 2 of accessing bindings ?
"BindingContext context = BindingUtils.getBindingContext();
DCBindingContainer bindingContainer = (DCBindingContainer)

context.getCurrentBindingsEntry(); "


Or the only way to evaluate above EL "#{bindings.allEmployees1.treeModel.makeCurrent}"
is through the method 3 resolveExpression() mentioned in your blog.

Kindly share your thoughts on this.

Jenice said...

Its an excellent article indeed. Both the terms are explained very nicely. Moreover the way you have described the functioning of both these controls taking respective usage and examples all my doubts are cleared. Thank you.
oracle ebs

Krishna said...

Hi:

I am not able to get getCurrentBindingsEntry() at all. Is this due to version?

Thanks
krishna