ADF Common Mistakes

Click here to load reader

  • date post

  • Category


  • view

  • download


Embed Size (px)

Transcript of ADF Common Mistakes


The following is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described for Oracles products remains at the sole discretion of Oracle.


Classic Mistakes with Oracle Application Development Framework Internal APIsDuncan Mills, Frank Nimphius Oracle Application Development Tools Product Management

Oracle Fusion Middleware


To err is human and every developer has the right to make mistakes. Don't abuse this privilege !


ADF Framework Mistakes


Using Internal Packages

ADF Faces, Trinidad and ADF Controller have an API package and an IMPL package Define logical framework abstractions Simplifies implementation of future product changes

APIs in public packages guaranteed to remain stable from release to release

APIs in IMPL package are internal-only Not to be used outside of framework Can be modified at any time without notice

Internal packages have "internal" in the naming


Binding Classes The Java in ADF

FacesCtrl* Bindings


FacesCtrlHierBindingFacesCtrlHierBinding binding expose the convenient methods I need. My expert tip: Always use these classes Example(s) public void onTableSelect(SelectionEvent selectionEvent) { // --- perform optional pre-processing here --- // RichTable _table = (RichTable ) selectionEvent.getSource(); CollectionModel model = (CollectionModel ) _table.getValue(); FacesCtrlHierBinding _binding = (FacesCtrlHierBinding) model.getWrappedData(); _binding.getTreeModel();

FacesCtrlHierBinding.FacesModel treeModel = (FacesCtrlHierBinding.FacesModel) treeModel.makeCurrent(selectionEvent); } // --- perform optional post-processing here --- //



Don't use FacesCtrlHierBinding and FacesCtrlHierNodeBinding directly Internal ADF Faces component model for tree, table and treeTable

Use EL in Java: #{bindings.allDepartments.treeModel.makeCurrent} Pro: Easy to use Does it right for all Data Control types Con: Requires knowledge about the PageDef definition

Use JUCtrlHierBinding, JUCtrlHierNodeBinding Pro: No knowledge about binding layer required Con: More code to write Requires advanced ADF skills


Replacing FacesCtrlHierBindingHow-to use JUCtrlHierBinding to make the selected table row the current row in the ADF Binding Example(s)public void onTableSelect(SelectionEvent selectionEvent) { // --- perform optional pre-processing here --- // RichTable _table = (RichTable ) selectionEvent.getSource(); CollectionModel model = (CollectionModel ) _table.getValue(); JUCtrlHierBinding _binding = (JUCtrlHierBinding) model.getWrappedData(); DCIteratorBinding iteratorBinding = _binding.getDCIteratorBinding(); Object _selectedRowData = _table.getSelectedRowData(); JUCtrlHierNodeBinding node = (JUCtrlHierNodeBinding) _selectedRowData ; Key rwKey = node.getRowKey(); iteratorBinding.setCurrentRowWithKey(rwKey.toStringFormat(true)); // --- perform optional post-processing here --- // }11

Other Mistakes

Unnecessary casting to Faces binding classes the reference to Faces Binding object is obtained while invoking non-faces specific binding methods. In this case, replaced FacesCtrl* binding with JUCtrl* binding

Caching as member variables Faces binding reference as member variable, exposing public getter and setter methods In general, don't cache the binding reference


ADF Bindings Mistakes


#{data.} Expression RootI can use the #{data} root in my EL to pull information from another Binding Container!


public static ApplicationModule getApplicationModuleForDataControl(String name){ return(ApplicationModule)JSFUtils.resolveExpression( "#{data." + name + ".dataProvider}"); }


#{data.} Expression Root

Sorry not reliable, may not always work #{data.} accesses the binding cache and may not work if Youve never instantiated that binding container Youve just had a fail-over on a cluster Plus its sloppy design if the UI needs the data, then say so!

Safer approach Create an explicit binding in the relevant pageDef and use #{bindings.*} In the finding the AM case, use an Action Binding findCtrlBinding() getDataControl() getDataProvider()


Accessing the "bindings" object using ELI access the ADF binding layer from EL in Java, using #{bindings} . Objections ?

Example(s)FacesContext fctx = FacesContext.getCurrentInstance(); ELContext elctx = fctx.getELContext(); Application app = fctx.getApplication(); ExpressionFactory efactory = app.getExpressionFactory(); ValueExpression vex = efactory.createValueExpression( elctx,"#{bindings}", Object.class); DCBindingContainer bindings = (DCBindingContainer) vex.getValue(elctx);


Accessing the "bindings" object using EL

Yes your honor objection ! You can use Java instead of EL (things have moved on)BindingContext bindingContext = BindingContext.getCurrent(); BindingContainer bindings = bindingContext.getCurrentBindingsEntry();


Using page fragmentsAdding a page fragment to my ADF page does not render the ADF bound data content

Example(s) ... ...


Using page fragments

JSP include only include the page content, not the ADF binding dependency Suggestions Copy the page fragment PageDef content into the PageDef file of the parent page Use ADF Faces page templates if the content you include is used on many pages Templates can have bindings Use ADF Regions Bounded task flows Can have their own bindings


Adding new RowsADF bound table does not show new rows created in View Object

Example(s)BindingContext bctx = BindingContext.getCurrent(); DCDataControl dc = bctx.findDataControl("AppModuleLocal"); ApplicationModule am = (ApplicationModule)dc.getDataProvider(); ViewObject vo = am.findViewObject("EmployeesVO1"); Row rw = vo.createRow(); rw.setAttribute("EmployeeId", 1234);


Don't fight the framework !


Adding new Rows

You almost created a mine field! Ignoring separation of layers Bypassing the ADF binding layer Making assumptions about the Data Control provider Ignoring our message of what ADF is designed for

Try working through the ADF binding layerBindingContext bctx = BindingContext.getCurrentInstance(); BindingContainer bindings = bctx.getCurrentBindingEntry() DCIteratorBinding dcIterator = (DCIteratorBinding) bindings.get("IteratorBindingName"); Row rw = dcIteratorBinding.getRowSetIterator().createRow(); rw.setNewRowState(Row.STATUS_INITIALIZED); //insert row to iterator dcIteratorBinding.getRowSetIterator().insertRow(rw); //make new row the current dcIteratorBinding.setCurrentRowWithKey( rw.getKey().toStringFormat(true));


Adding new Rows

Better if you have access to a table, tree or treeTable component Does not require knowledge about the binding layer, thus genericprivate void createRowInTable(RichTable table){ CollectionModel model = (CollectionModel ) table.getValue(); JUCtrlHierBinding _binding = (JUCtrlHierBinding) model.getWrappedData(); DCIteratorBinding dcIteratorBinding= _binding.getDCIteratorBinding(); Row rw = dcIteratorBinding.getRowSetIterator().createRow(); rw.setNewRowState(Row.STATUS_INITIALIZED); //insert row to iterator dcIteratorBinding.getRowSetIterator().insertRow(rw); //make new row the current Key k = rw.getKey(); dcIteratorBinding.setCurrentRowWithKey(k.toStringFormat(true)); }


ADF Controller Mistakes


Task Flow ParametersI used the expression editor to reference my Task Flow parameter But its always NULL?

Example arg #{pageFlowScope.myArg} java.lang.String


Task Flow Parameters

Dont be fooled by the expression editor! In this circumstance it cant quite be trusted.

By setting the attribute of the param-def you have re-mapped the data from the implied variable Probably a good idea to explicitly define a target bean in the task flow definition


PageFlow scope has Stale DataPageFlow scope returns old data. Is there a way to refresh the page flow scope ?

Exampleprivate Map scopeVar = AdfFacesContext.getCurrentInstance().getPageFlowScope(); public void buttonAction() { //the data read below is "old" !!! Object param1Value = scopeVar.get("param1"); ... }


PageFlow scope has Stale Data

Never store a scope map in a member variable of your bean It does not improve performance and you might be looking at stale dataBetterpublic void buttonAction(ActionEvent ae) { AdfFacesContext facesCtx = null; facesCtx = AdfFacesContext.getCurrentInstance() Map scopeVar = facesCtx.getPageFlowScope(); Object param1Value = scopeVar.get("param1"); ... }


PageFlow scope has Stale Data

This also applies for other scopesHow-to access memory scope data in ADFADFContext.getCurrent().getApplicationScope(); ADFContext.getCurrent().getSessionScope(); AdfFacesContext.getCurrentInstance().getPageFlowScope(); ADFContext.getCurrent().getRequestScope(); ADFContext.getCurrent().getViewScope();


"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil"- Donald Knuth


Extending AdfcExceptionHandlerI extended the ADFc exception handler, creating oracle.adf. configuration file in .adf/META-DATA/services