Wednesday, November 14, 2012

ADF Generator for Dynamic ADF BC and ADF UI

Often we implement solutions to automate ADF development, based on custom metadata stored in database. This is common requirement especially for reporting systems, where screens have very similar layout, just number of UI components differ. Reporting systems require parameters capture screens, each report may have different set of parameters. Instead of building separate ADF UI screen for each report - we can build only one, but dynamic. I will describe how we can achieve this with detail sample application.

I have presented this topic on OOW - OOW'12: Oracle ADF Implementations Around the Globe: Best Practices. It was promised by me to post a blog post with sample application - ADFDynamicReportUI.zip.

This sample consists four dynamic elements:

1. Dynamic VO
2. Two dynamic LOV's
3. Dynamic ADF UI Form


There is one proxy VO (read here about proxy VO concept - Proxy ViewObject and Dynamic Editable UI in ADF). This VO gets substituted by dynamic VO on runtime. I'm using this VO to be able to define iterator reference in page definition:


AM offers Client Interface method, this method is invoked from ADF Controller and is the main method responsible for dynamic structure construction:


First thing what this method does - dynamic VO creation along with the attribute creation. Select statement is defined from Dual, aliases for each of the attributes with default values are included (this typically will be retrieved from metadata). We have option to set different properties for the attribute - type, label, mandatory flag, etc.:


Next - LOV View Objects are created along with View Accessors. You should notice that second LOV is created with bind variable (Departments LOV will be filtered based on Location ID). All of this is done dynamically and can be based on custom metadata:


Sequence of the steps is important. LOV mapping with main VO attributes must be done after all View Accessors are defined. Here we map LOV's with attributes and also set LOV display type (Combo, LOV):


Last step - proxy VO is substituted with our dynamic VO:


Take a look now into helper method for LOV View Object creation. If SQL statement contains bind variable, you must set LOV View Object binding style to be BINDING_STYLE_ORACLE_NAME - otherwise will get error on runtime, related to bind variable index. If there are any bind variables, all of them must be defined:


There is another helper method, where View Accessors are defined. If LOV have bind variables, View Accessor bound attributes must be defined here. LOV metadata is constructed here also:


LOV metadata helper method constructs LOV representation:


Dynamic ADF BC code is invoked from ADF Controller, before fragment is accessed - through the custom method invocation:


On ADF UI we are using standard ADF component for dynamic UI - Dynamic Form:


This component is very good, because it doesn't require static attribute mapping in page definition, it allows to render dynamic ADF UI directly from iterator defined in page definition:


We can get parameters from UI easily, by accessing iterator from page definition:


Here you can see how dynamic ADF UI is rendered from dynamic ADF BC. Even validation is enforced, also choice list and LOV UI components are displayed:


Department Id is dependent on Location Id, change Location Id value:


Department Id LOV will be filtered by Location Id bind variable:


All this is generated dynamically from bottom to top:


Values are access and printed in the managed bean, from current row retrieved through the iterator:


12 comments:

mustafa yildirim said...

Hello,
Thanks for your another nice post. It is quite helpful for that subject i think.
Is there any sample used by EJB, Eclipselink like this one here-related in dynamic view/ui on ADF? I will be appreciated if you could share.

Andrejus Baranovskis said...

No, I dont have such sample. I would recommend to use ADF BC, if you access DB directly.

Andrejus

Alexis Lopez said...

Hi, thanks for writing such great posts. I was able to implement a dynamic reporting module based on this post. Regards.

Anonymous said...

Thanks for the post.
In my case i have a view object already defined. Now I want dynamically create LOV and attach to the view object attributes.

Regards
Azhar

Santiago Nieto Carrera said...

Thanks for this post.

I have detected an issue with this solution. If you create the dynamic component as dynamic Table, It doesn't work.

This is the stack trace:

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at oracle.jbo.ViewCriteriaItem.resolveResourceProperty(ViewCriteriaItem.java:2613)
at oracle.jbo.ViewCriteriaItem.resolveResourceProperty(ViewCriteriaItem.java:2608)
at oracle.jbo.ViewCriteriaItem.getControlType(ViewCriteriaItem.java:2828)
at oracle.adf.model.bean.DCVCItemValueRowAttrHints.resolveControlType(DCVCItemValueRowAttrHints.java:476)
at oracle.adf.model.bean.DCVCItemValueRowAttrHints.getControlTypeSkipOperCheck(DCVCItemValueRowAttrHints.java:188)
at oracle.adf.model.bean.DCVCItemValueRowAttrHints.getHint(DCVCItemValueRowAttrHints.java:224)
at oracle.jbo.uicli.binding.JUCtrlValueBinding.getHint(JUCtrlValueBinding.java:2353)
at oracle.adfinternal.view.faces.model.binding.FacesCtrlSearchBinding$AdfAttributeDescriptor._getControlType(FacesCtrlSearchBinding.java:3519)
at oracle.adfinternal.view.faces.model.binding.FacesCtrlSearchBinding$AdfAttributeDescriptor.isLOVDefined(FacesCtrlSearchBinding.java:3692)
at oracle.adfinternal.view.faces.model.binding.FacesCtrlSearchBinding$AdfFilterAttributeCriterion.(FacesCtrlSearchBinding.java:4998)
at oracle.adfinternal.view.faces.model.binding.FacesCtrlSearchBinding$AdfFilterConjunctionCriterion._loadCriterionList(FacesCtrlSearchBinding.java:4645)
at oracle.adfinternal.view.faces.model.binding.FacesCtrlSearchBinding$AdfFilterConjunctionCriterion.getCriterionMap(FacesCtrlSearchBinding.java:4568).


This is happening when you check the filterable table option.

Andrejus Baranovskis said...

I was testing filterable option with dynamic table, it works fine for me. Which ADF version you are using?

Andrejus

Santiago Nieto Carrera said...

jdev version is 12c (12.1.2.0).

I have created a dynamic table with the ADF Table wizard, checking the option: Generate columns dynamically at runtime.

Andrejus Baranovskis said...

This post for 11g, I would need to test if same works with 12c. This is different.

Andrejus

Vishwanath N said...

Hello Andrejus,

Thanks for the useful post on dynamic form.

I am trying to implement this feature in my project. Am facing NullPointerException as below while trying to run the page.

<_handleException> ADF_FACES-60098:Faces lifecycle receives unhandled exceptions in phase RENDER_RESPONSE 6
java.lang.NullPointerException
at oracle.adfinternal.view.faces.dynamic.DynamicForm.isRefreshNecessary(DynamicForm.java:506)
at oracle.adfinternal.view.faces.dynamic.DynamicForm.createChildren(DynamicForm.java:373)
at oracle.adfinternal.view.faces.dynamic.DynamicForm.encodeBegin(DynamicForm.java:283)

Can you help me out?

Thanks,
Vishwanath

Andrejus Baranovskis said...

Try to recreate the iterator - http://andrejusb.blogspot.com/2013/03/adf-generator-for-dynamic-adf-bc-and.html

Andrejus

Santiago Nieto Carrera said...

Hi,

Could you test this application in jdev12c?

I have an application in which I create the Entities, ViewDefs and VOs at runtime in model project, and VOs are rendered as table with <af:dynamicComponent.

I want to use the af:query panel with the ViewCriteria "__ImplicitViewCriteria__", but I get the same error.

jdev 12c.

Andrejus Baranovskis said...

I have a similar app for 12c, it is using completely custom generated UI, you can change it to use dynamicComponent: http://andrejusb.blogspot.com/2014/11/adaptive-form-with-dynamic-adf-lov.html

Andrejus