Wednesday, June 8, 2011

Creating Task Flow bindings on the fly

A very common demand from the community was support for adding regions at run time. The good news is that 11.1.2 release has support for adding regions dynamically which is now well supported by a task flow binding layer as well. Wow...excited? Please see
21.10 Configuring a Page To Render an Unknown Number of Regions in developers fusion developers guide to learn more about this topic. Let me give you a quick overview on the implementation. Its very easy.


1. Build the logic to return TaskFlowBindingAttributes list for dynamic task flows

First step is to build a managed bean to hold your business logic for building list of oracle.adf.controller.binding.TaskFlowBindingAttributes as shown in the following code snippet.

 private List<TaskFlowBindingAttributes> taskFlowBindings = new ArrayList<TaskFlowBindingAttributes>();  
   
 public void buidTaskflowBindings(){  
   
  TaskFlowBindingAttributes tfBindAttr1 = new TaskFlowBindingAttributes();  
  tfBindAttr1.setId("region1");  
  tfBindAttr1.setTaskFlowId(new TaskFlowId("/WEB-INF/dept-task-flow-definition.xml", "dept-task-flow-definition"));  
  taskFlowBindings.add(tfBindAttr1);  
    
  TaskFlowBindingAttributes tfBindAttr2 = new TaskFlowBindingAttributes();  
  tfBindAttr2.setId("region2");  
  tfBindAttr2.setTaskFlowId(new TaskFlowId("/WEB-INF/emp-task-flow-definition.xml", "emp-task-flow-definition"));  
  tfBindAttr2.setParametersMap("#{pageFlowScope.MyBean.parameterMap}");  
  taskFlowBindings.add(tfBindAttr2);  
 }  
   
 public List<TaskFlowBindingAttributes> getTaskFlowBindings() {  
  return taskFlowBindings;  
 }  
   

2. Generate the executable entry for multi task flow in the page definition file

Switch to the binding tab of your page, click on the '+' icon under the Executables section to generate the binding for multiTaskFlow. Please see the following image.


You may need to key in a unique identifier for the <multiTaskFlow> entry, and a value for taskFlowList as well. The taskFlowList will take an EL expression that returns the list of TaskFlowBindingAttributes at run time. In our case the method getTaskFlowBindings() returns the list(please refer this method in above code snippet).

Note: The multi task flow binding (multiTaskFlow) in the page definition identifies a list of bounded task flows used in the ADF region.

  <multiTaskFlow id="multiRegion1"   
  taskFlowList="#{pageFlowScope.MyBean.taskFlowBindings}"  
  xmlns="http://xmlns.oracle.com/adf/controller/binding" activation="deferred"/>  


3. Build the UI to host regions at run time

The last step is building the UI to host regions at run time. This example uses af:forEach for adding regions at run time as shown in the following page snippet.

 <af:forEach var="tf" items="#{bindings.multiRegion1.taskFlowBindingList}">  
  <af:region value="#{tf.regionModel}" id="reg#{tf.name}"/>  
 </af:forEach>  


Notes(from Fusion Developers Guide):

  • Limit the number of ADF regions that you create in a page to 10.
  • Each task flow binding inherits attributes defined for the multi task flow binding unless you override this behavior using the methods exposed by TaskFlowBindingAttributes.
  • Each task flow binding inherits parameters defined in the multi task flow binding in addition to those defined using the parametersMap property.

Download

You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11.1.2.0.0 (11g R2) + HR Schema]

A glance at the implementation

Run the main.jsf page and click on the 'Display More Taskflows' button.
You may notice that two task flows are getting added on the screen when you click on the button.


Learn More ...

There are a lot more points like this. If  you are curious to learn the internals of the ADF Business Components and ADF Binding Layer,  the following book is for you - Oracle ADF Real World Developer’s Guide.
More details about this book can be found in this post- http://jobinesh.blogspot.in/2012/07/pre-order-your-copy-of-oracle-adf-real.html



12 comments:

Selva said...

Nice feature :)

amit said...
This comment has been removed by the author.
amit said...

Hi Jobinesh,
I followed this post and the regions displayed as you explained.

Then I tried little different approach where I have a tabbed view on my page. On this tab, inside a showDetail I put the below code and it works.


af:showDetailItem text="Detail" id="sdi1"
af:region value="#{bindings.dynamicListBTFList.taskFlowBindingList[0].regionModel}"
id="r1" rendered="true"
af:showDetailItem


Later, I tried to add a new tab dynamically to display a region displaying one of the binded taskflow using below code. You see that the value expression is same.

In this case of dyanmically adding the region, the new tab displays nothing!


RichRegion region = new RichRegion();
region.setId("Region_" + (n++));

FacesContext context = FacesContext.getCurrentInstance();
ValueExpression vex =
context.getApplication().getExpressionFactory().createValueExpression(context.getELContext(),
"#{bindings.dynamicListBTFList.taskFlowBindingList[0].regionModel}",
Object.class);
region.setValueExpression("value", vex);

RichShowDetailItem newShowDetailItem = new RichShowDetailItem();
newShowDetailItem .setDisclosed(Boolean.TRUE);
newShowDetailItem .setRendered(Boolean.TRUE);

newShowDetailItem .setId("DynamicTabID_" +
(n++));
newShowDetailItem.getChildren().add(region);
mainTabbedPanel.getChildren().add(employeeShowDetailItem);
AdfFacesContext.getCurrentInstance().addPartialTarget(mainTabbedPanel);

Please suggest if this is possible to do.

Jobinesh said...

Amit,
sorry for the delayed response. Look like this support/fix(programmatically adding taskflow bindings) will be available on future release

oceans said...

Hi,
I have a scenario where I have a parent page which is more like a dashboard where I have four regions which shows data for monitoring purpose of different reports of the application.

* All there regions are put inside a panel Box with the command link to refresh the data in the regions.
* The regions are dynamic regions where different task flow are assigned at runtime governed by their backing bean TaskFlow Id's (No input parameter for taskFlows).

The problem I face is, I am able to restart the taskFlows in the regions to their default activity by hitting the refresh the link using this small piece off code.

BindingContext bctx = BindingContext.getCurrent();
BindingContainer bindings = bctx.getCurrentBindingsEntry();
DCTaskFlowBinding taskflowBinding = (DCTaskFlowBinding) bindings.get("dynamicRegion2");
taskflowBinding.getRegionModel().refresh(FacesContext.getCurrentInstance());

But the iterators in the page fragments of the task flows are not getting me the fresh values in the DB, instead they give me the values that are fetched during the initial loading.

So can anyone kindly tell me how to refresh the regions from the parent page such that it refresh's the taskflow and get a fresh values from DB very time it loads.

Thanks and Regards,
Vijai

Jobinesh said...

Vijai,
If you use VO, drag and drop the executeQuery action displayed in the data control panel to your taksflow and mark it as default method activity for your taskflow.Rest will be taken care by the framework

oceans said...

Hi Jobinesh,

Cool idea, does makes sense. Thank you.

Regards,
Vijai

amit said...

Programmatic adding taskflow bindings is still not available in Build JDEVADF_11.1.2.1.0_GENERIC_110907.2314.6081.

Siddi said...

Hi Jobinesh,
Thanks for Sharing this valuable test App.
I ran your testApp.i was unable to retrieve,parameter map in jspx, with this syntax '#{tf.parameterMap['DepartmentId']}' , where tf is var in foreach. Can you please tell me how to access this parameter map in jsff/jspx ?
Thanks in Advance,
Siddi

Thanh Hoang said...

Hi amit,

About adding Region programmatically:

you gotta specify region :
RichRegion region = new RichRegion();
region.setVisible(true);
region.setRendered(true);

It will be OK.

MadFlex said...

Hi, is there any option to create runtime showdetailsItem with different table?

ElGueuzifié said...

Hi Jobinesh,

Nice post.

Do you have any ideas how to do it in release 1 ?

Thanks.

Ghazi