You are on page 1of 83

1

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.

<Insert Picture Here>

Classic Mistakes with Oracle Application Development Framework Internal APIs


Duncan 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

FacesCtrlHierBinding
FacesCtrlHierBinding binding expose the convenient methods I need. My expert tip: Always use these classes Example(s)
<af:table value="#{bindings.allLocations.collectionModel}" selectionListener="#{myBean.onTableSelect}"/> 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 --- // }

FacesCtrlHierBinding

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
10

Replacing FacesCtrlHierBinding
How-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

12

ADF Bindings Mistakes

13

#{data.} Expression Root


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

Example(s)
<af:outputText value="#{data.demo_v1PageDef.LastName}"/>

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

14

#{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()

15

Accessing the "bindings" object using EL


I 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);

16

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();

17

Using page fragments


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

Example(s)
<af:document id="d1"> ... <f:subview id="sv1"> <jsp:include page="/allDepartments.jsff"/> </f:subview> ... </af:document>

18

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

19

Adding new Rows


ADF 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);

20

Don't fight the framework !

21

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 layer


BindingContext 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));

22

Adding new Rows

Better
if you have access to a table, tree or treeTable component Does not require knowledge about the binding layer, thus generic
private 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)); }

23

ADF Controller Mistakes

24

Task Flow Parameters


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

Example
<input-parameter-definition> <name>arg</name> <value> #{pageFlowScope.myArg} </value> <class> java.lang.String </class> <required/> </input-parameter-definition>

25

Task Flow Parameters

Dont be fooled by the expression editor!


In this circumstance it cant quite be trusted.

By setting the <value> 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

26

PageFlow scope has Stale Data


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

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

27

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 data
Better
public void buttonAction(ActionEvent ae) { AdfFacesContext facesCtx = null; facesCtx = AdfFacesContext.getCurrentInstance() Map<String, Object> scopeVar = facesCtx.getPageFlowScope(); Object param1Value = scopeVar.get("param1"); ... }

28

PageFlow scope has Stale Data

This also applies for other scopes


How-to access memory scope data in ADF
ADFContext.getCurrent().getApplicationScope(); ADFContext.getCurrent().getSessionScope(); AdfFacesContext.getCurrentInstance().getPageFlowScope(); ADFContext.getCurrent().getRequestScope(); ADFContext.getCurrent().getViewScope();

29

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

30

Extending AdfcExceptionHandler
I extended the ADFc exception handler, creating oracle.adf. view.rich.context.ExceptionHandler configuration file in .adf/META-DATA/services

Example(s)
public class MyExceptionHandler extends AdfcExceptionHandler{ public void handleException(FacesContext facesContext, Throwable throwable, PhaseId pahseId){ String error = throwable.getMessage(); ... super.handleException(...); } }

31

Extending AdfcExceptionHandler

Ouch ! Hold on .... ADFc exception handling usually is sufficient and you don't need to customize the exception handler
Not all exceptions are accessible for the ADFc controller

If you need to extend the default exception handler


Don't use AdfcExceptionHandler Internal class that you should not use Even Product Managers got this wrong

Extend ExceptionHandler and re-throw exceptions you don't know how to handle See next slide how to do it right ...
32

Extending AdfcExceptionHandler
import oracle.adf.view.rich.context.ExceptionHandler; public class CustomExceptionHandler extends ExceptionHandler { public CustomExceptionHandler() { super(); } public void handleException(FacesContext facesContext, Throwable throwable, PhaseId phaseId) throws Throwable { String error_message; error_message = throwable.getMessage(); if (error_message != null && error_message.indexOf("ADF_FACES-30108") > -1) { ExternalContext ectx = facesContext.getExternalContext(); ectx.redirect("faces/SessionExpired.jspx"); } else { throw throwable; } } }

33

Extending AdfcExceptionHandler

Configuration
Create oracle.adf.view.rich.context.Exceptionhandler text file and store it in .adf\META-INF\services you need to create the services folder Add the absolute name of your custom exception handler Java class that extends ExceptionHandler

Configuration is framework wide


Not to be deployed with ADF Library

34

queueActionEventInRegion
If it bends, bend it! I found a cool way to execute ADF bindings contained in an ADF Region Feeling lucky today.

Example(s)
richRegion.queueActionEventInRegion( "#{bindings.Delete.execute}", null, null, false, 0, 0, PhaseId.INVOKE_APPLICATION); }

35

queueActionEventInRegion
See here ...

public void queueActionEventInRegion( javax.el.MethodExpression actionExpression, javax.el.MethodExpression launchListenerMethodExpression, javax.el.MethodExpression returnListenerMethodExpression, java.lang.Boolean useWindow, java.lang.Integer windowWidth, java.lang.Integer windowHeight, javax.faces.event.PhaseId phaseId )

36

I don't care about what anything was DESIGNED to do, I care about what it CAN do.
Gene Kranz, Apollo 13 (Movie, 1995)

37

queueAction

Queues an ActionEvent so that it behaves as if you queued it on a command component inside of the region
Used to navigate region from outside Navigation cases are discoverable

Though executes any method, it is not what this is designed for


Available actions are not discoverable Result of method invocation may not display Works against TaskFlow encapsulation

38

Product Demonstration
queueActionEventInRegion

39

Redirect to Current Page


My page needs to redirect to current page. Using JSF ExternalContext redirect() works but seems to loose ADF controller state

Example
FacesContext fctx = FacesContext.getCurrentInstance(): ExternalContext ectx = fctx.getExternalContext(); UIViewRoot root = fctx.getViewRoot(); String viewId = root.getViewId(); ectx.redirect("/faces/"+viewId);

40

Redirect to Current Page

JSF doesn't know about ADF Controller and ADF Region states Use ControllerContext to create redirect URL
private void redirectToSelf(){ FacesContext fctx = FacesContext.getCurrentInstance(); ExternalContext ectx = fctx.getExternalContext(); String viewId = fctx.getViewRoot().getViewId(); ControllerContext controllerCtx = null; controllerCtx = ControllerContext.getInstance(); String activityURL = controllerCtx.getGlobalViewActivityURL(viewId); try{ ectx.redirect(activityURL); } catch (IOException e) { //Can't redirect e.printStackTrace(); } }

41

Navigation in Bounded Task Flow


JSF NavigationHandler.handleNavigation() is not recommended for use to navigate in bounded task flows though it appears to work. Why ? And what should I use instead ? Example
FacesContext fctx = FacesContext.getCurrentInstance(); NavigationHandler nh = fctx.getApplication().getNavigationHandler(); nh.handleNavigation(fctx, null, "doEmployeesFiltered");

Navigation case

42

Navigation in Bounded Task Flow

Let's do the "why" first


Directly invocation of methods on the NavigationHandler doesn't conform with JSF specification Bypasses JSF lifecycle invoke application phase is missed out Pending changes are not submitted E.g, using ADF, no MDS commit would happen It's a bad thing to do even if you don't notice incorrect behavior The specification assumes that the framework will invoke the NavigationHandler in response to an ActionEvent

43

Navigation in Bounded Task Flow

I have a several options for you


1. Use setViewId() on the controller context Navigates to viewId in bounded task flow Does not navigate to routers and method call activities 2. queue an action event on a command component 3. Use queueActionEventOnRegion Example
ControllerContext ccontext = ControllerContext.getInstance(); //set the viewId to display String viewId = "EmployeesView"; ccontext.getCurrentViewPort().setViewId(viewId);

44

Navigation in Bounded Task Flow

A several options for you


1. Use setViewId() on the controller context 2. queue an action event on a command component Component can be hidden 3. Use queueActionEventOnRegion
private void onQueueC3ButtontAction() { FacesContext fctx = FacesContext.getCurrentInstance(); UIViewRoot root = fctx.getViewRoot(); RichCommandButton button = (RichCommandButton) root.findComponent("r1:cb3"); ActionEvent actionEvent = new ActionEvent(button); actionEvent.queue(); }

45

Navigation in Bounded Task Flow

A couple of options for you


1. Use setViewId() on the controller context 2. queue an action event on a command component 3. Use queueActionEventOnRegion Queues an action by its navigation case
Private void navUsingQueueAction(ActionEvent actionEvent) { UIComponent comp = actionEvent.getComponent(); while(!(comp instanceof RichRegion)){ comp = comp.getParent(); } ((RichRegion) comp).queueActionEventInRegion( createMethodExpressionFromString("doEmployees"), null, null, false, 0, 0,PhaseId.INVOKE_APPLICATION); }

46

Navigation in Bounded Task Flow

Helper Method
private MethodExpression createMethodExpressionFromString(String s){ FacesContext fctx = FacesContext.getCurrentInstance(); ELContext elctx = fctx.getELContext(); ExpressionFactory exprFactory = fctx.getApplication().getExpressionFactory(); MethodExpression methodExpr = exprFactory.createMethodExpression( elctx, s, null, new Class[]{}); return methodExpr; }

47

Product Demonstration
Navigation in bounded Task Flow

48

Expression Language Mistakes

49

Accessing Managed Beans #{requestScope.<>}

I prefix all my managed bean EL references with the scope the bean is in, for example, #{requestScope. BeanName.propertyName}

Example(s)
<af:outputText value="#{requestScope.BeanName.LastName}"/>

50

Accessing Managed Beans #{requestScope.<>}

Doesnt always work for beans in default Servlet scopes


requestScope, sessionScope, applicationScope Bypasses JavaServer Faces managed bean facility Only looks for in-memory objects Does not instantiate managed beans Only good idea if looking up memory attributes you know exist or you want to create

Works for ADF specific scopes


viewScope, pageFlowScope, backingBeanScope ADFc controller takes care of managed bean instantiation if configuration is available

51

JavaServer Faces Mistakes

52

JSF Lifecycle - immediate="true"


I have a command button that when pressed should update a text field. Just its not working Arrrgs

Example(s)
<af:inputtext value="#{mybacking.firstName}" .../> <af:commandButton action="#{mybacking.updateFirstNameVal}" immediate="true" .../>

53

JSF Lifecycle - immediate="true"

Understand the JSF Request Lifecycle JSF Phases


Restore View Apply Request Values Process Validation Update Model Values Invoke Application Render Response

Immediate means "execute first" not "execute only"


Command button is special case Use "immediate" on button to bypass model update

54

ADF Lifecycle "extends" JSF Lifecycle


JSF Lifecycle Phases
Restore View

ADF Lifecycle Phases


JSF Restore View Init Context Prepare Model New Context Prepare Model Prepare Render For Same View Init Context

Apply Request Values Process Validation Update Model Values

JSF Apply Request Values JSF Process Validation JSF Update Model Values Validate Model Updates

For Same View Render Response

Invoke Application

JSF Invoke Applications Meta Data Commit

Prepare Render

Changed View?

yes

no

Render Response

55

Product Demonstration
Immediate = true

56

One to Print on a T-Shirt

Immediate = true PartialSubmit = true PartialSubmit = true Immediate = true

57

ADF Faces Component Mistakes

58

Mixing JSF and HTML


HTML helps me to create the layout I want. Sometimes however it seems to break ADF Faces. Is this a bug ?

Example(s)
<af:form> <table> <tr valign="top"> <td><af:inputText ... label="search" /></td> <td><af:commandButton ... text="go" /></td> </tr> </table> ... </af:form>

59

Mixing JSF and HTML

HTML only theoretically works in JSF


JSF 1.2 synchronizes lifecycle so that HTML "waits" for JSF Not all components accept HTML as a child component HTML binds to data using JSTL, which can only supports deferred expressions ${ ... }

ADF Faces RC layout component handle geometry management, which may conflict with HTML ADF Faces components canbe accessed and manipulated from managed beans HTML elements don't participate in PPR Recommendation: Don't mix and match !

60

Examples

61

Inline Style CSS


Some components seem to ignore CSS. Others apply it wrong

Example(s)
<af:inputText label="PhoneNumber" id="it2" inlineStyle="background-color:Red; color:Green;"/>

????

62

Inline Style CSS

ADF Faces Components are far more complex than simple HTML elements Styles are applied to the root DOM element, not the component itself ContentStyle styles the inner area of a component Solution: Skinning
<tbody> <tr id="j_id_id16" <td> <label for="j_id_id16::content"> PhoneNumber </label> </td> <td> <input id="j_id_id16::content" type="text" value="650.507.9833"/> </td></tr> </tbody>

63

Nesting Tables Failed Use Case I


I want nested ADF Faces tables. This does not seem to work. Example(s)

64

Nesting Tables Failed Use Case I

No layout boundaries

Sample already optimized as much as possible


Its as good as it gets Used tree binding for m/d to work (!) Auto row sizing to trim table layout Still, not a good idea Messes with ADF Faces geometry management

65

Not everything that compiles can be shipped!

66

af:forEach, af:iterator

af:forEach and af:Iterator tags are often confused af:Iterator


Behaves like a table without chrome Stamps children Can be used with JSF DataModel and Trinidad CollectionModel Child items can access EL variables defined on a parent e.g. "row" in a table

67

af:forEach, af:iterator

af:forEach
Replaces JSTL c:forEach, which does not support varStatus Only iterates java.util.Lists
Does not support java.util.Collection

Use to generate components For example: <f:selectItem > Components are remembered by their index items created by <af:forEach> should not be added, removed or reordered once the component tree has been created Use cases
Components should be created conditionally based item in the loop. Different JSP includes, page templates, and dynamic declarative components should be included per loop iteration

68

Nesting Tables Failed Use Case II


Need help! I am trying to build a nested table. Doesn't work in ADF Faces. Must be a bug. Screw you Oracle !

Example(s)
<af:table value="#{bindings.allDepartments.collectionModel}"> ... <af:column> <af:table ... Value="#{bindings.dependentEmployees.collectionModel"> ... </af:table> </af:column> </af:table>

69

Nesting Tables

Tables are rendered on the server


Valid children is af:column Valid children are any output component and layout element Tables are stamped, which means that a row is not a new instance of a component No single table row refresh No query issued to fetch m/d dependent data per row If nested layouts are needed, use af:forEach or afIterator

70

af:iterator in table columns


My table rows have nested information I want to show to users. How do I do this then ?

71

af:iterator in table columns

Create a detail node binding Use #{row.children} in af:iterator


Var="row"

72

Opening popup dialogs


I want to open a popup from a command link in a table using af:showPopupBehavior. The popup does not show and instead the page is refreshed

Example(s)
<af:commandButton text="commandButton 1" id="cb1"> <af:showPopupBehavior popupId="popup1" triggerType="action" align="afterEnd" alignId="it1"/> </af:commandButton> <af:popup id="popup1" ...> ... </af:popup>

73

Opening popup dialogs

Popups must be opened using a partial submit Its a lighweight dialog that is part of the page HTML output
Repainting the page closes the popup

74

File Upload in ADF Region


File uploads don't work in ADF Regions. I am scratching my head in disbelief

Same code works in JSPX page I see no exception

75

File Upload in ADF Region

ADF Region uses page fragments Page fragments don't have an af:form tag on their own af:form tag is in parent page, or if parent page is fragment too, in the parent's parent page Make sure af:form tag has usesUpload="true" set

76

JavaScript Mistakes

77

Using the Browser DOM


I am a JavaScript expert and "DOM" is my corporate nickname.: DOM, James DOM

Example(s)
function cancelEventAndUpdateWithDom(evt){ evt.cancel(); var txtfield1 = document.getElementById("it1::content"); txtfield1.value = "Hello OOW 2010" }

78

Using the Browser DOM

Accessing the browser DOM operates on HTML markup


Markup is generated by component renderers HTML output may change without notice as it is an implementation detail of the JSF component renderer HTML markup does not provide same set of component properties Allow PPR

Better
If you need to use JavaScript, use the ADF Faces client framework
function cancelEventAndUpdateWithAdfFaces(evt){ evt.cancel(); var txtfield1 = AdfPage.PAGE.findComponentByAbsoluteId('it1'); txtfield1.setValue("Hello OOW 2010"); }

79

Using the Browser DOM


Tried what you said just doesn't work. Back to direct DOM manipulation ?

Example(s)
var txtfield1 = AdfPage.PAGE.findComponentByAbsoluteId('it1');

Always returns null


<af:inputText id="it1" value="#{SampleBean.txt1}"/> <af:commandButton text="Update" id="cb1" partialSubmit="true"> <af:clientListener method="cancelEventAndUpdateWithAdfFaces" type="action"/> </af:commandButton>

80

Using the Browser DOM

ADF Faces is performance optimized


Most of the components rendered byserver side generated HTML markup JavaScript objects are created for components with rich functionality Developers can enforce JavaScript object to be rendered Setting component property clientComponent = "true" or ... ... apply clientListener
<af:inputText id="it1" value="#{SampleBean.txt1}" clientComponent="true"/> <af:commandButton text="Update" id="cb1" partialSubmit="true"> <af:clientListener method="cancelEventAndUpdateWithAdfFaces" type="action"/> </af:commandButton>

81

82

Related Oracle Press Books

Quick Start Guide to Oracle Fusion Development Oracle JDeveloper 11g Handbook Oracle Fusion Developer Guide

83

You might also like