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:


24 comments:

  1. 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.

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

    Andrejus

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

    ReplyDelete
  4. 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

    ReplyDelete
  5. 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.

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

    Andrejus

    ReplyDelete
  7. 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.

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

    Andrejus

    ReplyDelete
  9. 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

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

    Andrejus

    ReplyDelete
  11. 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.

    ReplyDelete
  12. 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

    ReplyDelete
  13. Hi, Thanks for your great post, It's very helpful! We have another requirement: whether can we change sql of LOV VO at run time? for example: I have 2 pages, one page has 2 buttons, another is to show form of dynamic table, one column has dynamic LOV, when press button 1, LOV show sql 1 list, when press button 2, LOV show sql 2 list

    Kelvin

    ReplyDelete
  14. You could use LOV switcher functionality and still have two LOV's in the background.

    Regards,
    Andrejus

    ReplyDelete
  15. Hi

    Thank you very much for this post. I was able to implement a dynamic form

    But the attributes which were present in form can i show those attribute below the form as table in read only mode??

    If so kindly let me know

    ReplyDelete
  16. Hi,
    On using this approach to create VO, View Accessor I am running into 2 issues. Can you help with this?

    I am not using a dynamiic form, instead have created a transient attribute on existing vo and associating the view accessor at runtime.

    1. First approach, I tried to drag n dropo my transiient attribute and load the lov from bean method. With This, I was able to acess the ListBinding loaded programatically as mentioned by you. But was not able to access the values of ListBinding. I was using listBinding.getValueList() and listBinding.getLabelList() methods to show the lov. But these were always returned null and hence could not populate the selectItems.

    2. In second approach, I tried to drop the transient attribute ass Lov and mapped it to the programatic lov id in page def xml. With this approach, While the screen is rendered I am getting "Definition -1 of type Attribute is not found in Vo". On debugging I noticed View DEfinition is looking to a result Index to load the Row Set, And in this case it is always returning as -1. Hence the error.

    Can you please suggest me the right approach?

    ReplyDelete
  17. Hi Andrejus,

    How do we apply page level validation for the jsff which is created.

    eg : If i want to apply email, integer validation on jsff how can we achieve it above scenario?

    Thanks,
    Rohit

    ReplyDelete
  18. You can add validation rules to ADF BC attributes programmatically.

    Regards,
    Andrejus

    ReplyDelete
  19. Hi Andrejus,
    your job is wonderful, as ever.
    I'm trying to use the dynamic table but I have some problem in setting the SelectionListener and the filterable options.
    In a comment you wrote that filterable options work fine with you.
    Could you please share the method you used?
    And for the SelectionListener: have you found how can be substituted the call to the collectionModel.makeCurrent method?

    Thanks and best regards.

    Marco

    ReplyDelete
  20. Thanks for feedback. I noted down your question. I will try to post next blog with answers.

    Andrejus

    ReplyDelete
  21. Thank you!!!
    I'll be waiting :)

    ReplyDelete
  22. Hi Andrejus
    i notice that you application download links are down is any other links can be posted

    ReplyDelete
  23. This is true for all old samples prior to 2014, you can download all such samples from Google Archive - https://code.google.com/archive/p/jdevsamples/downloads

    Regards,
    Andrejus

    ReplyDelete
  24. Hi Andrejus Baranovskis,

    In of my application I used dynamic VO. but i got the weird behavior like in QA environment i am getting oracle.jbo.domain.date datatype for date attribute and on production I am getting java.sql.timestamp datatype . can you help me why i am getting this type of behavior? erything is same on both the environments. and when i restart the server then issue is resolved on prod.


    How can i handle this behaviour?

    ReplyDelete